JavaScript中Promise的執(zhí)行順序舉例詳析
概述
理解 Promise 的執(zhí)行順序時,需要牢記以下兩點:
微任務(wù)與宏任務(wù)的優(yōu)先級:
- 微任務(wù):
Promise.then()、catch、finally是微任務(wù)。 - 宏任務(wù):
setTimeout、setInterval是宏任務(wù)。 - 微任務(wù)的優(yōu)先級高于宏任務(wù):在一次事件循環(huán)中,先清空所有的微任務(wù)隊列,再執(zhí)行下一個宏任務(wù)。
- 微任務(wù):
Promise 是基于微任務(wù)實現(xiàn)的:
- 當(dāng)一個
Promise的狀態(tài)變?yōu)?nbsp;resolved或rejected時,它的.then()回調(diào)會被加入微任務(wù)隊列,等待當(dāng)前任務(wù)(包括微任務(wù))完成后執(zhí)行。
- 當(dāng)一個
示例代碼分析
代碼分析
以下代碼可以幫助理解 Promise 和 setTimeout 的執(zhí)行順序:
console.log("script start");
setTimeout(() => {
console.log("setTimeout 1");
}, 0);
Promise.resolve()
.then(() => {
console.log("promise 1");
return Promise.resolve().then(() => {
console.log("promise 2");
});
})
.then(() => {
console.log("promise 3");
});
setTimeout(() => {
console.log("setTimeout 2");
}, 0);
console.log("script end");
執(zhí)行過程解析
同步任務(wù):立即執(zhí)行
console.log("script start")輸出"script start".setTimeout的兩個回調(diào)函數(shù)被放入 宏任務(wù)隊列,等待事件循環(huán)調(diào)度。Promise.resolve()被調(diào)用,then()的回調(diào)被放入 微任務(wù)隊列。
輸出結(jié)果:
script start
script end主線程執(zhí)行完同步任務(wù)后,開始執(zhí)行微任務(wù)隊列
- 微任務(wù)隊列的順序如下:
- 第一個
.then()輸出"promise 1"并返回一個新的Promise。 - 新的
Promise.then()輸出"promise 2"。 - 第二個
.then()輸出"promise 3"。
- 第一個
輸出結(jié)果:
promise 1 promise 2 promise 3
- 微任務(wù)隊列的順序如下:
清空微任務(wù)隊列后,開始執(zhí)行宏任務(wù)隊列
- 宏任務(wù)隊列的兩個
setTimeout回調(diào)依次執(zhí)行,輸出"setTimeout 1"和"setTimeout 2"。
輸出結(jié)果:
setTimeout 1 setTimeout 2
- 宏任務(wù)隊列的兩個
最終輸出
綜合以上,代碼的輸出順序為:
script start script end promise 1 promise 2 promise 3 setTimeout 1 setTimeout 2
總結(jié)
- 同步任務(wù)優(yōu)先執(zhí)行,輸出
script start和script end。 - 微任務(wù)隊列優(yōu)先于宏任務(wù)隊列。
Promise.then()的回調(diào)會依次進(jìn)入微任務(wù)隊列。setTimeout的回調(diào)進(jìn)入宏任務(wù)隊列,最后執(zhí)行。
(拓展)問題補(bǔ)充
如果第一個then不是返回return promise,而是直接執(zhí)行一個Promise.resolve().then(() => { console.log("promise 2"); });結(jié)果是不是
會變成 promise 1 → promise 3 → promise 2。結(jié)果是的。
為什么會這樣?
當(dāng) Promise.resolve().then() 不通過 return 將內(nèi)部的 Promise 鏈接到外部 then 時,promise 2 的執(zhí)行不再是當(dāng)前鏈的一部分,它會被單獨添加到 微任務(wù)隊列的末尾,導(dǎo)致執(zhí)行順序的變化。
示例代碼
以下是修改后的代碼:
console.log("script start");
Promise.resolve()
.then(() => {
console.log("promise 1");
Promise.resolve().then(() => {
console.log("promise 2");
});
})
.then(() => {
console.log("promise 3");
});
console.log("script end");
執(zhí)行過程解析
同步任務(wù)
- 輸出
"script start"。 - 主線程繼續(xù),將第一個
Promise.then()的回調(diào)加入 微任務(wù)隊列。 - 輸出
"script end"。
當(dāng)前輸出:
script start script end
- 輸出
微任務(wù)隊列開始執(zhí)行
- 執(zhí)行第一個
.then(),輸出"promise 1"。
在此回調(diào)中,一個新的微任務(wù)(promise 2的回調(diào))被加入 微任務(wù)隊列末尾。 - 執(zhí)行第二個
.then()的回調(diào),輸出"promise 3"。
當(dāng)前輸出:
promise 1 promise 3
- 執(zhí)行第一個
微任務(wù)隊列剩余任務(wù)
- 微任務(wù)隊列中剩余的任務(wù)是
promise 2的回調(diào),輸出"promise 2"。
最終輸出:
promise 2
- 微任務(wù)隊列中剩余的任務(wù)是
總輸出結(jié)果
綜合以上,完整的輸出順序是:
script start script end promise 1 promise 3 promise 2
關(guān)鍵點解析
鏈?zhǔn)秸{(diào)用和微任務(wù)隊列當(dāng)你不通過
return將一個新的Promise鏈接到當(dāng)前then,它的回調(diào)會獨立加入 微任務(wù)隊列的末尾,而不是成為當(dāng)前鏈的一部分。對比:返回 Promise如果
return Promise.resolve().then(...),那么promise 2的執(zhí)行會成為當(dāng)前鏈的一部分,順序為promise 1 → promise 2 → promise 3。
改變的核心代碼
獨立的微任務(wù):
Promise.resolve().then(() => { console.log("promise 2"); });作為鏈的一部分:
return Promise.resolve().then(() => { console.log("promise 2"); });
兩種寫法的區(qū)別在于是否將新的 Promise 加入當(dāng)前鏈。
總結(jié)
到此這篇關(guān)于JavaScript中Promise的執(zhí)行順序舉例詳析的文章就介紹到這了,更多相關(guān)JS Promise執(zhí)行順序內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JS中的回調(diào)函數(shù)(callback)講解
回調(diào)函數(shù)是一段可執(zhí)行的代碼段,它作為一個參數(shù)傳遞給其他的代碼,其作用是在需要的時候方便調(diào)用這段(回調(diào)函數(shù))代碼,這篇文章主要介紹了JS中的?回調(diào)函數(shù)(callback),需要的朋友可以參考下2022-12-12
基于JavaScript實現(xiàn)網(wǎng)頁計算器
這篇文章主要為大家詳細(xì)介紹了基于JavaScript實現(xiàn)網(wǎng)頁計算器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-05-05
JS獲取月的最后一天與JS得到一個月份最大天數(shù)的實例代碼
本篇文章主要是對JS獲取月的最后一天與JS得到一個月份最大天數(shù)的實例代碼進(jìn)行了介紹,需要的朋友可以過來參考下,希望對大家有所幫助2013-12-12

