Promise中then的鏈式回調

看題!

new Promise((resolve, reject) => {
            reject(1); // 確定promise狀態爲rejected
        }).then((fullfilled) => {
            console.log(fullfilled);
        }, (rejected) => {
            console.log(rejected, '2-1'); // 執行這裏,then方法必須返回一個新的Promise實例,這個沒有明式 return 值,便隱式觸發新promise的fullfilled狀態,進入下一個then的fullfilled回調
        }).then((fullfilled) => {
            console.log(fullfilled, '3-1'); // 執行這裏,因上一步resolve未傳值,所以fullfilled爲undefined,繼續隱式觸發fullfilled回調
        }, (rejected) => {
            console.log(rejected, '3-2');
        }).then((fullfilled) => {
            console.log(fullfilled, '4-1'); // 執行這裏
            return Promise.reject(5); // 明式返回rejected的promise
        }, (rejected) => {
            console.log(rejected, '5-1');
        }).catch((error) => {
            console.log(error, '6-1'); // 執行這裏,被catch捕獲,error爲上一步reject傳入的值。因Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的別名,用於指定發生錯誤時的回調函數,所以catch同樣返回一個新的promise,若沒有顯示指定,便同上執行隱式操作
        }).then(fullfilled => {
            console.log(fullfilled, '7-1'); // 執行這裏
        }, rejected => {
            console.log(rejected, '7-2');
        })

結果爲:

1 "2-1"
undefined "3-1"
undefined "4-1"
5 "6-1"
undefined "7-1"

總結:

  1. Promise.prototype.then()返回的是一個新的Promise實例(注意,不是原來那個Promise實例)。因此可以採用鏈式寫法,即then方法後面再調用另一個then方法。
  2. then方法中若有顯式 return 一個新的 promise(包括fullfilled和rejected)則顯示執行。若無顯式指定,則隱式觸發新promise的pending->fullfilled狀態變更,進入下一個thenfullfilled回調。
  3. Promise.prototype.catch()方法是.then(null, rejection).then(undefined, rejection)的別名,用於指定發生錯誤時的回調函數,所以catch同樣返回一個新的promise,若沒有顯示指定,便執行隱式操作。

建議:

  • 不要在then方法裏面定義 Reject 狀態的回調函數(即then的第二個參數),總是使用catch方法。

以上留有歧義者歡迎指出!

參考資料:
PromiseA+ 規範地址
中文翻譯PromiseA+ 規範
解讀Promise內部實現原理

這裏也結合promise提一下 event loop,JavaScript執行流程由函數調用棧與異步隊列(宏任務與微任務組成)。

注意這裏 macrotask microtask 分別表示異步任務的兩種分類。js運行過程中,JS 引擎會將所有任務按照類別分到兩個隊列中,首先在 macrotask 的隊列(也叫 task queue)中取出第一個任務,執行完畢後取出 microtask 隊列中的所有任務順序執行;之後再取 macrotask 任務,周而復始,直至兩個隊列的任務都取完。(任務的執行都是在函數調用棧中完成的)。

上一個例子:

console.log('start');
setImmediate(() => {
  console.log(1);
  new Promise((resolve, reject) => {
    resolve(4);
  }).then((data) => {
    console.log(data);
  })
});
setTimeout(() => {
  console.log(2);
});
new Promise((resolve, reject) => {
  resolve(3);
}).then((data) => {
  console.log(data);
})
console.log('end');

結果:

start
end
3
1
4
2

其中chrome中,setImmediate優先於setTimeout執行

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章