溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

v8是如何實現(xiàn)更快的await

發(fā)布時間:2022-03-25 09:51:30 來源:億速云 閱讀:164 作者:iii 欄目:web開發(fā)

本篇內容介紹了“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è)相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI