您好,登錄后才能下訂單哦!
本篇內容介紹了“v8是如何實現(xiàn)更快的await ”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!
Example
首先看下代碼:
const p = Promise.resolve();
(async () => {
await p;
console.log("after:await");
})();
p.then(() => {
console.log("tick:a");
}).then(() => {
console.log("tick:b");
});
以 node v10 的執(zhí)行結果為準,node v8 的實現(xiàn)是不符合ECMAScript 標準
優(yōu)秀的程序員總是能以簡單的例子解釋復雜的原理。代碼很簡單,但是執(zhí)行結果可能出乎很多人意料:
tick:a
tick:b
after:await
如果你已經猜對了,本文的關鍵內容你已經掌握,不用往下看了:)。
為什么 after:await會出現(xiàn)在tick:a之后,甚至是tick:b之后? 要理解其中的原理,我們可以做一個小實驗。
將 await 翻譯成 promise
v8博客中是以偽代碼的方式解釋await的執(zhí)行邏輯:
原圖 https://v8.dev/_img/fast-async/await-under-the-hood.svg
我們可以用promise語法寫成:
function foo2(v) {
const implicit_promise = new Promise(resolve => {
const promise = new Promise(res => res(v));
promise.then(w => resolve(w));
});
return implicit_promise;
}
按照同樣的方式,可以將文章開頭的代碼轉換成:
const p = Promise.resolve();
(() => {
const implicit_promise = new Promise(resolve => {
const promise = new Promise(res => res(p));
promise.then(() => {
console.log("after:await");
resolve();
});
});
return implicit_promise;
})();
p.then(() => {
console.log("tick:a");
}).then(() => {
console.log("tick:b");
});
經過一些瑣碎的調試,發(fā)現(xiàn)問題真正的關鍵代碼是這一句: const promise = new Promise(res => res(p));
Resolved with another promise
了解 Node.js 或瀏覽器的事件循環(huán)的童鞋都知道,resolved promise 的回調函數(shù)(reaction)是放在一個單獨的隊列MicroTask Queue中。 這個隊列會在事件循環(huán)的階段結束的時候被執(zhí)行,只有當這個隊列被清空后,才能進入事件循環(huán)的下一個階段。
我們知道一個 promise 的 .then 回調的返回值可以是一個任意值,也可以是另外一個 promise。 但是后者的處理邏輯可能有點反直覺。
在深入之前,我們簡單說一下 promise 的幾種狀態(tài):
我們說一個 promise 是 resolved 的,表示它不能被再次 fulfill 或 reject, 要么是被 fulfill,要么被 reject(這兩種情況,promise 均有一個確定的 non-promise result), 要么遵循另外一個 promise(隨之 fulfill 或 reject)
我們說一個 promise 是 unresolved 的,表示它尚未被 resolve
當一個 promise(假設叫 promiseA。方便引用) 被 resolve,并且去遵循另外一個 promise(叫 p) 時,執(zhí)行邏輯和前面兩種 resolve 情況非常不同,用偽代碼表示則是:
addToMicroTaskQueue(() => { // 任務A
// 使用 .then 方法,將 promiseA 的狀態(tài) 和 p 綁定
p.then(
resolvePromiseA, // 任務B
rejectPromiseA
);
});
我們一步一步來分析:
首先,我們在MicroTask Queue添加任務A,該任務在 ECMAScript 標準 中被定義為 PromiseResolveThenableJob
任務A,主要目的是使 promiseA 遵循 p 的狀態(tài),將兩者的狀態(tài)關聯(lián)起來。
由于我們例子中 p 已經是 resolved(狀態(tài)為fulfilled)的,所以立即將resolvePromiseA任務B 添加到MicroTask Queue中
在 resolvePromiseA 執(zhí)行后,promiseA 才是 resolved (狀態(tài)為 fulfilled,值為 p 的 fulfilled value)
我們可以看到,從 new Promise(res=>res(p)) 到該調用返回的 promise 真正被 resolve 至少需要兩次microtick——在我們的例子中,是遍歷了兩次 MicroTask Queue
這個時候,我們終于可以理清楚開頭代碼的執(zhí)行順序:
01月28日更新,之前微任務隊列里面的任務沒有考慮順序,這里做一下修改,以下隊列里的任務是順序有關,從左往右,左邊的先執(zhí)行
1、當代碼執(zhí)行完后
MicroTask Queue有兩個任務:PromiseResolveThenableJob,tick:a
2、開始執(zhí)行 runMicrotasks()
MicroTask Queue變成:resolvePromiseA,tick:b
console: tick:a
3、MicroTask Queue沒有清空,繼續(xù)執(zhí)行隊列中的任務
MicroTask Queue變成:after:await
console: tick:a, tick:b
4、繼續(xù)執(zhí)行,清空MicroTaak Queue
console: tick:a, tick:b, after:await
“v8是如何實現(xiàn)更快的await ”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。