// syntax,executor 是生產程式碼,最終會產生結果,傳到 promise,promise 物件有 2 個內部屬性,// state 描述 promise 狀態,一開始 pedding => fullfilled or rejected// result 任意值,一開始 undefined => value or errorlet promise =newPromise(function(resolve, reject) {// executor (生产者代码,"singer")});
// 會自動呼叫 executor,executor 會接收 resolve、reject 2 個參數。let promise =newPromise(function(resolve, reject) {// the function is executed automatically when the promise is constructed// after 1 second signal that the job is done with the result "done"setTimeout(() =>resolve("done"),1000);});
let promise =newPromise(function(resolve, reject) {// after 1 second signal that the job is finished with an errorsetTimeout(() =>reject(newError("Whoops!")),1000);});
// executor 只會有一個結果,另一個結果會被忽略。let promise =newPromise(function(resolve, reject) {resolve("done");reject(newError("…")); // 被忽略setTimeout(() =>resolve("…")); // 被忽略});// 可以使用任何類型的參數帶入 reject,但建議使用 Error 物件// 通常 executor 會執行一些異步程式,這時需要一些時間才能得到結果。我們可以立即返回結果,當任務// 已經完成。let promise =newPromise(function(resolve, reject) {// not taking our time to do the jobresolve(123); // immediately give the result: 123});// promise 的內建屬性 state and result,不能從消費程式碼取得,但可以透過// .then/.catch/.finally 等方法取得
Consumers: then, catch, finally
消費程式碼可以得知生產結果,透過 .then, .catch and .finally等方法。
then
// syntax,成功時執行第 1 個參數,失敗時執行第 2 個參數promise.then(function(result) { /* handle a successful result */ },function(error) { /* handle an error */ });// 成功let promise =newPromise(function(resolve, reject) {setTimeout(() =>resolve("done!"),1000);});// resolve runs the first function in .thenpromise.then( result =>alert(result),// shows "done!" after 1 second error =>alert(error) // doesn't run);// 失敗let promise =newPromise(function(resolve, reject) {setTimeout(() =>reject(newError("Whoops!")),1000);});// reject runs the second function in .thenpromise.then( result =>alert(result),// doesn't run error =>alert(error) // shows "Error: Whoops!" after 1 second);// 只返回成功結果let promise =newPromise(resolve => {setTimeout(() =>resolve("done!"),1000);});promise.then(alert); // shows "done!" after 1 second
catch
// 只返回失敗結果,可以用 .then(null, errorHandlingFunction) 或 .catch(errorHandlingFunction)// .catch(f) 是 .then(null, f) 的簡寫let promise =newPromise((resolve, reject) => {setTimeout(() =>reject(newError("Whoops!")),1000);});// .catch(f) is the same as promise.then(null, f)promise.catch(alert); // shows "Error: Whoops!" after 1 second
finally
// 就像 try {...} catch {...} 有 finally,promise 也有 finally// .finally(f) 很像 .then(f, f),當 promise 完成他會被執行無論成功或失敗。// finally 適合使用在清空記憶體newPromise((resolve, reject) => {/* do something that takes time, and then call resolve/reject */})// runs when the promise is settled, doesn't matter successfully or not.finally(() => stop loading indicator).then(result => show result, err => show error)// .finally(f) 跟 .then(f, f) 的差別// 1. finally 沒有參數// 2. finally 傳遞 result 參數// 成功newPromise((resolve, reject) => {setTimeout(() =>resolve("result"),2000)}).finally(() =>alert("Promise ready")).then(result =>alert(result)); // <-- .then handles the result// 失敗newPromise((resolve, reject) => {thrownewError("error");}).finally(() =>alert("Promise ready")).catch(err =>alert(err)); // <-- .catch handles the error object// 3. .finally(f) 比 .then(f, f) 簡潔// 當 promise 執行完畢結果會立即回傳// an immediately resolved promiselet promise =newPromise(resolve =>resolve("done!"));promise.then(alert); // done! (shows up right now)
Example: loadScript
functionloadScript(src, callback) {let script =document.createElement('script');script.src = src;script.onload= () =>callback(null, script);script.onerror= () =>callback(newError(`Script load error for ${src}`));document.head.append(script);}// 重新改寫functionloadScript(src) {returnnewPromise(function(resolve, reject) {let script =document.createElement('script');script.src = src;script.onload= () =>resolve(script);script.onerror= () =>reject(newError(`Script load error for ${src}`));document.head.append(script); });}// 使用let promise =loadScript("https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js");promise.then( script =>alert(`${script.src} is loaded!`), error =>alert(`Error: ${error.message}`));promise.then(script =>alert('One more handler to do something else!'));
Promises
Callbacks
Promises allow us to do things in the natural order. First, we run loadScript(script), and .then we write what to do with the result.
We must have a callback function at our disposal when calling loadScript(script, callback). In other words, we must know what to do with the result beforeloadScript is called.
We can call .then on a Promise as many times as we want. Each time, we’re adding a new “fan”, a new subscribing function, to the “subscription list”. More about this in the next chapter: Promises chaining.