簡體   English   中英

帶有阻塞代碼的 setTimeout 行為

[英]setTimeout behaviour with blocking code

這是我的測試代碼(在這里小提琴):

console.log('Before wait');
setTimeout(function () { console.log('Yo!'); }, 1000);
var start = Date.now();
while (Date.now() < start + 3000) {}
console.log('After wait');

這是 Chrome 中事件的時間線:

  • 時間 0 秒:打印“等待前”
  • 時間 3 秒:打印“After wait”,然后在“Yo!”之后立即打印

這種行為是否符合規范? 為什么不是

  • 時間 0 秒:打印“等待前”
  • 時間 3 秒:打印“等待后”
  • 時間 4 秒:打印“Yo!”

?

JavaScript 是單線程的。 如果某個代碼塊使用執行線程,則不能執行其他代碼。 這意味着您的setTimeout()調用必須等到主執行(忙等待while循環的那個)完成。

這是發生的事情:您安排setTimeout()在一秒后執行,然后阻塞主線程 3 秒。 這意味着當您的繁忙循環完成時,超時已經晚了 2 秒 - 並且 JS 引擎試圖通過盡快調用您的超時來跟上 - 即立即。

其實這個:

while (Date.now() < start + 3000) {}

是 JavaScript 中最糟糕的事情之一。 您持有 JavaScript 執行線程 3 秒鍾,並且無法執行其他事件/回調。 通常瀏覽器會在這段時間內“凍結”。

setTimeout的延遲與調用時的確切時間點有關。 當您還在忙着等待時,它就會過期。 因此它將在控制返回事件循環的下一個時刻執行。

編輯:

規范在這一點上有點含糊,但我想這是有意且唯一直接的解釋:

setTimeout(函數,毫秒)

此方法在經過指定的毫秒數后調用該函數一次,直到被調用 clearTimeout 取消。 這些方法會返回一個 timerID,該 ID 可用於后續調用 clearTimeout 以取消間隔。

當您在 setTimeout 調用后運行忙等待循環時,您不會為“喲!”留出時間。 打印出來,因為 Javascript 運行時正忙於您的循環(實際上,由於循環條件的繼續評估,空語句也使其忙碌)。

您應該始終避免這種忙等待循環,因為在該循環完成之前,在該窗口中不能調用或運行其他任何東西。

不確定它是否可以幫助您,但此問題已在以下位置進行了解釋: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Run-to-completion

出於這個原因,第二個參數表示最短時間——而不是保證時間。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM