都是本人理解,筆記大致概念底洗,不詳細也并非完全正確,所以僅供參考亥揖。
同步珊擂、異步
JS 代碼的執(zhí)行费变,可以理解為任務(wù)的執(zhí)行,則其中有同步任務(wù)和異步任務(wù)挚歧。
同步任務(wù)是指在主線程上的任務(wù)扛稽,只有前面一個執(zhí)行完畢,才會再執(zhí)行下一個滑负。
同步任務(wù)好理解,異步任務(wù)的執(zhí)行主要是以下步驟:
- 主線程任務(wù)進行矮慕,若發(fā)現(xiàn)異步任務(wù),將其移入任務(wù)隊列
- 主線程任務(wù)結(jié)束痴鳄,開始執(zhí)行任務(wù)隊列的異步任務(wù)
- 任務(wù)隊列任務(wù)進行瘟斜,若發(fā)現(xiàn)異步任務(wù),將其移入任務(wù)隊列后
- 重復步驟3直至沒有任務(wù)隊列沒有任務(wù),結(jié)束螺句。
Promise
都知道異步任務(wù)的 callback 的循環(huán)嵌套會讓人抓狂虽惭,所以就有了 Promise,Promise主要解決了JS異步任務(wù)代碼的可讀性問題蛇尚。
Promise 的三種狀態(tài)
- pending:初始狀態(tài),非成功或失敗
- fulfilled:操作成功完成
- rejected:操作失敗
Promise 的狀態(tài)的改變是不可逆的,所以它只會有:
- pending -> fulfilled
- pending -> rejected
同步亲雪、異步、Promise 的執(zhí)行順序
有個問題义辕,Promise 是不是異步操作?先看代碼:
setTimeout(() => {
console.log(1);
}, 0);
new Promise(resolve => {
console.log(2);
resolve();
console.log(3);
}).then(res => {
console.log(4);
});
console.log(5);
正確結(jié)果是:2灌砖、3、5基显、4、1 撩幽,來一一解析。
先忽略1和5窜醉,如果說 Promise 是同步的,那么應(yīng)該是 2拜英、4、3居凶,但結(jié)果為什么是2、3排监、4杰捂?
猜想是 Promise 將 resolve(); 的方法加了某種延遲舆床,這種延遲不加入任務(wù)隊列,而僅僅是等待 Promise 初始化函數(shù)結(jié)束而開始執(zhí)行谷暮,所以結(jié)果是 2、3湿弦、4。
實際上腾夯,這種操作是存在的,稱之為微任務(wù)蝶俱,微任務(wù)的執(zhí)行順序介于主線程和任務(wù)隊列之間。
PS:任務(wù)隊列的任務(wù)也稱之為宏任務(wù)
所以榨呆,在上述代碼中,1被插入任務(wù)隊列等待积蜻,而 Promise 初始函數(shù)先輸出 2,再因為 resolve(); 為微任務(wù)而先輸出3宙拉,然后因為微任務(wù)的執(zhí)行順序低于主線程,所以輸出 5丙笋,最后微任務(wù)執(zhí)行完畢,執(zhí)行 then 輸出 4不见,最后才執(zhí)行到任務(wù)隊列,輸出 1稳吮,所以最后的結(jié)果是:2、3灶似、5、4酪惭、1。
如果宏任務(wù)包含微任務(wù)春感,那么先后順序是砌创?
答案:執(zhí)行宏任務(wù) > 執(zhí)行包含的微任務(wù) > 執(zhí)行下一個宏任務(wù)。
new Promise(resolve1 => {
console.log(1);
setTimeout(() => {
resolve1();
}, 0);
setTimeout(() => {
console.log(2);
}, 0);
})
.then(() => {
return new Promise(resolve2 => {
resolve2();
console.log(3);
});
})
.then(() => {
console.log(4);
});
console.log(5);
答案嫩实?1、5甲献、3、4慨灭、2
解析一下:主線程進行,Promise 初始化函數(shù)里輸出 1氧骤,將宏任務(wù) setTimeout - resolve1(); 和setTimeout - 2 放入隊列桶略,輸出 5诲宇,主線程結(jié)束际歼,執(zhí)行宏任務(wù)setTimeout - resolve1(); 姑蓝,執(zhí)行宏任務(wù)下的微任務(wù) resolve1() > then,新的 Promise 的執(zhí)行函數(shù)中旭愧,輸出 3,發(fā)現(xiàn)微任務(wù) resolve2()输枯,執(zhí)行 then 輸出4占贫,此宏任務(wù)結(jié)束桃熄,下一個宏任務(wù) setTimeout - 2 型奥,輸出 2,結(jié)束厢汹。
總結(jié)
Promise并非異步的,僅僅因為resolve和reject方法為微操作界弧,所以會先執(zhí)行初始函數(shù)體,進而再執(zhí)行then夹纫,所以會讓人誤以為是異步的。
ES5 寫 Promise
貼代碼總覺得不夠深層舰讹,寫一下自己的理解,參照 Promise 的三種狀態(tài)钻洒,可以知道有這些屬性锄开。
- 狀態(tài):記錄 Promise 的狀態(tài)
- 成功值:成功后的返回值
- 失敗值:失敗后的返回值
- 成功回調(diào)方法:成功后的執(zhí)行方法素标,即 then
- 失敗回調(diào)方法:失敗后的執(zhí)行方法萍悴,即 catch
- resolve方法:切換狀態(tài)至成功,并執(zhí)行成功回調(diào)方法
- reject方法:切換狀態(tài)至失敗计维,并執(zhí)行失敗回調(diào)方法
- then方法:傳入成功回調(diào)方法和失敗函數(shù)方法撕予,將此存儲Promise中鲫惶,切換狀態(tài)時進行對應(yīng)調(diào)用实抡。
過程
- 當 new 一個 Promise 時,將初始函數(shù)執(zhí)行赏淌,然后將 then 或 catch 的回調(diào)函數(shù)存儲,當切換狀態(tài)成功或切換狀態(tài)失敗函數(shù)時六水,取出存儲的成功回調(diào)或失敗回調(diào)進行執(zhí)行盒延。
- 像 then 的鏈式調(diào)用缩擂,實質(zhì)是返回一個新的 Promise 即可添寺。
- then 的支持傳入成功和失敗回調(diào),而 catch 實際上是執(zhí)行 then 且僅傳入失敗回調(diào)博脑。