好家伙,本篇為做題思考 書接上文 題目如下: 1.請給出下列代碼的輸出結果,並配合"消息隊列"寫出相關解釋 async function foo() { console.log(2); console.log(await Promise.resolve(8)); console.log(9); } ...
好家伙,本篇為做題思考
書接上文
題目如下:
1.請給出下列代碼的輸出結果,並配合"消息隊列"寫出相關解釋
async function foo() { console.log(2); console.log(await Promise.resolve(8)); console.log(9); } async function bar() { console.log(4); console.log(await 6); console.log(7); } console.log(1); foo(); console.log(3); bar(); console.log(5);
好我們公佈答案:
(1) 列印 1;
(2) 調用非同步函數 foo();
(3)(在 foo()中)列印 2;
(4)(在 foo()中)await 關鍵字暫停執行,向消息隊列中添加一個期約在落定之後執行的任務;
(5) 期約立即落定,把給 await 提供值的任務添加到消息隊列;
(6) foo()退出;
(7) 列印 3;
(8) 調用非同步函數 bar();
(9)(在 bar()中)列印 4;
(10)(在 bar()中)await 關鍵字暫停執行,為立即可用的值 6 向消息隊列中添加一個任務;
(11) bar()退出;
(12) 列印 5;
(13) 頂級線程執行完畢;
(14) JavaScript 運行時從消息隊列中取出解決 await 期約的處理程式,並將解決的值 8 提供給它;
(15) JavaScript 運行時向消息隊列中添加一個恢復執行 foo()函數的任務;
(16) JavaScript 運行時從消息隊列中取出恢復執行 bar()的任務及值 6;
(17)(在 bar()中)恢復執行,await 取得值 6;
(18)(在 bar()中)列印 6;
(19)(在 bar()中)列印 7;
(20) bar()返回;
(21) 非同步任務完成,JavaScript 從消息隊列中取出恢復執行 foo()的任務及值 8;
(22)(在 foo()中)列印 8;
(23)(在 foo()中)列印 9;
(24) foo()返回。
所以答案是
1
2
3
4
5
6
7
8
9
好了,結束了,沒什麼問題了
步驟也解釋清楚了
但是我隱約感到了不對勁
怎麼會是123456789呢?
foo()應該是先恢復的,但是這裡明顯bar()先恢復了
我們上機試一下
誒,結果不對
前面地12345都沒有問題,6789的輸出變成了8967
我們主要來看和6789有關的輸出欄位
我們再來仔細地看看前面地解釋,並把關鍵解釋划出來
(4)(在 foo()中)await 關鍵字暫停執行,向消息隊列中添加一個期約在落定之後執行的任務;
(5) 期約立即落定,把給 await 提供值的任務添加到消息隊列;
(6) foo()退出;
(10)(在 bar()中)await 關鍵字暫停執行,為立即可用的值 6 向消息隊列中添加一個任務;
(11) bar()退出;
(13) 頂級線程執行完畢;
(14) JavaScript 運行時從消息隊列中取出解決 await 期約的處理程式,並將解決的值 8 提供給它;
(15) JavaScript 運行時向消息隊列中添加一個恢復執行 foo()函數的任務;
(16) JavaScript 運行時從消息隊列中取出恢復執行 bar()的任務及值 6;
我們回顧一下消息隊列
一個 JavaScript 運行時包含了一個待處理消息的消息隊列。. 每一個消息都關聯著一個用以處理這個消息的回調函數。
再補充一個關於await的知識點
等到 await 右邊的值可用了,JavaScript 運行時會向消息 隊列中推送一個任務,這個任務會恢復非同步函數的執行。
我們試著把這個消息隊列畫出來
(有點抽象,但應該能看懂)
這樣,我們就會發現, 因為Promise.resolve(8)被多處理了一次,導致了foo()方法後恢復
所以bar()先恢復了
那麼實際上機又是怎麼回事呢?
(書裡面有行小字被我忽略了,後面又找到了)
TC39 對 await 後面是期約的情況如何處理做過一次修改。修改後,本例中的 Promise.resolve(8)只會生成一個 非同步任務。
因此在新版瀏覽器中,這個示例的輸出結果為 123458967。實際開發中,對於並行的非同步操作我們通常 更關註結果,而不依賴執行順序。——譯者註
實際上機的消息隊列
原先的兩步處理變成了一步
搞定了,原來如此