若是await 同一個 Promise 兩次會怎麼樣?

先看下面這道面試題:javascript

let counter = 0;
const increment = new Promise(resolve => {
  counter++;
  resolve();
});
await increment;
await increment;
console.log(counter); // 結果是什麼?

你認爲 counter 的值是什麼?前端

什麼是 promise ?這是否意味着「稍後再作」?java

實際上應該把 promise 當作是一個狀態機。程序員

promise 以「pending」狀態開始它的生命週期。若是你要在這個狀態下查詢結果,則必須排隊。面試

根據 ECMAScript 標準文檔中的描述(https://tc39.es/ecma262/),上面 Promise 構造函數會當即調用咱們的執行器函數。它的 counter++ 反作用運行。不帶任何參數調用resolve(),在 promise 上存儲一個 undefined 結果,並將其狀態提高爲「fulfilled」。segmentfault

第一個 await 運行。 await 等同於在你的 promise 上運行.then(onFulfilled),將 onFulfilled 設置爲「前面的代碼」。這項工做做爲微任務進入隊列。 JavaScript 以先進先出的順序執行微任務;控制最終返回給咱們的函數。promise

第二個 await 沒有什麼不同的地方。它建立一個微任務給我 promise 的結果並提早運行代碼,而後等待 JavaScript 進行調度。服務器

反作用只在 Promise 構建期間運行過一次,因此 counter1.微信

咱們推遲了工做嗎?沒有。promise 是同步建立和執行的。可是咱們使用了 await 來處理其餘微任務。多線程

那麼應該怎樣推遲工做?

const microtask = Promise.resolve()
.then(() => console.log('hello from the microtask queue'));

const macrotask = new Promise(resolve =>
  // 排隊宏任務
  setTimeout(() => {
    console.log('hello from the macrotask queue');
    resolve();
  })
  // 沒有解決,promise 仍處於 pending 狀態
);

// 這是最早輸出的; 咱們成功地推遲了工做
console.log('hello from the original execution context');

// yield 調度器; 運行 .then() 並輸出日誌
await microtask;
// yield 調度器;  promise 的狀態是 fulfilled ,因此沒有日誌輸出
await microtask;

// yield 調度器; 執行全部微任務,而後運行宏任務並輸出日誌
await macrotask;
// yield 調度器; promise 已經完成,因此沒有日誌輸出
await macrotask;

Promise 構造函數是同步運行的,可是咱們沒必要同步調用 resolve()Promise.prototype.then 也推遲了工做。

Promise 構造函數和 Promise.prototype.then 都不會重複工做。

這意味着 promise 能夠用來記住異步計算。若是你用了一個 promise,並且想要稍後再次用到它的結果,應該考慮保留 promise 而不是它的結果。

173382ede7319973.gif


本文首發微信公衆號:前端先鋒

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章

歡迎掃描二維碼關注公衆號,天天都給你推送新鮮的前端技術文章


歡迎繼續閱讀本專欄其它高贊文章:


相關文章
相關標籤/搜索