這是我正在運行的代碼:
async function sleep(ms) {
const start = new Date();
while (new Date() - start < ms) { };
}
const start = new Date();
sleep(5000).then(() => console.log("1!"));
console.log(new Date() - start, "ms");
sleep(5000).then(() => console.log("2!"));
console.log(new Date() - start, "ms");
我期望的輸出是這樣的:
1 ms (or some other small number of ms)
2 ms (or some other small number of ms)
1!
2!
相反,我看到的是:
5000 ms
10005 ms
1!
2!
我對此有點困惑。首先,為什么兩個睡眠函式沒有異步運行?為什么第二個睡眠呼叫直到第一個呼叫完成才開始?其次,如果第二個呼叫直到第一個呼叫完成才開始,為什么要1!列印 before 2!?
如果我將sleep(ms)函式更改為以下內容(在另一個 StackOverflow 問題中建議),代碼將按預期作業:
function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
如果我sleep(ms)在不使用超時的情況下用一些緩慢的計算替換,我應該期待什么?
uj5u.com熱心網友回復:
JavaScript 并不是真正的多執行緒。它依賴于兩件事來產生這種錯覺:
計算機真的非常快,并且通常可以完成任何需要立即完成的人類可以分辨的事情
因為它們很快而世界很慢,所以計算機花費大量時間等待某事發生,并且在此期間可以有利可圖地做其他事情
基本上,JavaScript 運行一個執行緒,直到它完成,或者正在等待某些事情發生(例如異步網路呼叫),此時 JavaScript 將切換到另一個執行緒,如果有的話。
您的第一個sleep()功能是忙等待。它消耗 100% CPU 什么都不做。更重要的是,它永遠不會給另一個執行緒運行的機會。promise 解決方案以 JavaScript 的方式完成它:它幾乎立即結束(從而給其他執行緒一個運行的機會)并SetTimeout在其他執行緒沒有運行時使用它來重新獲得控制權(以異步方式)。
uj5u.com熱心網友回復:
標記為的函式async不與其他代碼同時運行的原因是async不會導致函式異步(!)。相反,這個關鍵字將函式標記為回傳 Promise,并且還啟用了一些語法糖,例如 await。
這意味著這async與執行緒、任務或其他語言已知的任何其他并發原語完全無關。在 JavaScript 程式中,所有可見代碼都以阻塞方式在單個執行緒中執行,并一直運行到完成。這就是長while回圈阻塞程式流的原因。
為什么setTimeout按預期作業?因為實際運行的代碼是setTimeout和res回呼,僅此而已。在后臺,事件回圈確保res最終呼叫它,但處理它的機制對開發人員是隱藏的。
讓我們深入研究第一種情況。
會發生什么,一步一步,是這樣的 - 請注意,用戶代碼以不間斷的方式運行完成:
- 第一個睡眠()運行到結束,并且它的回傳值的。那么()方法被呼叫,它入列一個回呼的所謂microtask(其中將記錄
1!)的事件回圈執行很快 - 第一個 console.log 運行
- 第二個 sleep() 運行完成,并呼叫其回傳值的 .then() 方法,該方法又將另一個微任務入隊
- 第二個 console.log 運行
- <用戶程式現在已經完成,但是事件回圈中還有一些東西需要JS引擎處理!>
- 事件回圈處理第一個微任務:
() => console.log("1!") - 事件回圈處理第二個微任務:
() => console.log("2!") - <事件回圈現在是空的 - 執行結束>
如果你sleep()用 setTimeout替換函式體,你會注意到它setTimeout本身執行起來很快——它所做的只是將一些東西排入佇列以便事件回圈稍后處理并回傳。這就是執行流程不會被阻塞的原因。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/354843.html
標籤:javascript 节点.js
