又被node的eventloop坑了,此次是node的鍋

近日在論壇上看到一篇文章講node和谷歌瀏覽器的eventloop的區別,由於看到寫的還不錯,我表示了確定。但沒過多久一位壇友卻說node11結果不同,我說怎麼可能不同。接着壇友貼了個代碼,我試着運行了一下,啪啪打臉!node

一探究竟

先上被啪啪打臉的代碼:git

setTimeout(() => {
  console.log('timer1');
  Promise.resolve().then(function() {
    console.log('promise1');
  });
}, 0);
setTimeout(() => {
  console.log('timer2');
  Promise.resolve().then(function() {
    console.log('promise2');
  });
}, 0);
複製代碼

瞭解node的eventloop的同窗應該會這樣想:github

  1. 理想狀況下這個就是一開始將兩個setTimeout放進timers的階段。
  2. 等到時間到達後運行timer1,把promise1的Promise放入timers的下一階段微任務隊列中,同理繼續運行timers的階段,執行timer2,把promise2的Promise放入timers的下一階段微任務隊列中。
  3. 直到timers隊列所有執行完,纔開始運行微任務隊列,也就是promise1和promise2.

那麼若是機器運行良好就是如下結果:promise

timer1
timer2
promise1
promise2
複製代碼

node10運行結果確實是這樣,是沒問題的。但node11運行後竟然是:瀏覽器

timer1
promise1
timer2
promise2
複製代碼

挺吃驚的,但吃驚事後仍是仔細去翻node的修改日誌,在node 11.0 的修改日誌裏面發現了這個:markdown

  • Timers
    • Interval timers will be rescheduled even if previous interval threw an error. #20002
    • nextTick queue will be run after each immediate and timer. #22842

而後分別看了20002和22842的PR,發如今 #22842 在lib/timers.js裏面有如下增長:異步

timer.png

immediate.png

這兩個是什麼意思呢?oop

提示一下runNextTicks()就是process._tickCallback()。用過的可能知道這個就是除了處理一些異步鉤子,而後就是執行微任務隊列的。因而我增長了兩行process._tickCallback()在setTimeout方法尾部,再使用node10運行,效果果真和node11一致,代碼以下:spa

setTimeout(() => {
    console.log('timer1');
    Promise.resolve().then(function() {
        console.log('promise1');
    });
    process._tickCallback(); // 這行是增長的!
}, 0);
setTimeout(() => {
    console.log('timer2');
    Promise.resolve().then(function() {
        console.log('promise2');
    });
    process._tickCallback(); // 這行是增長的!
}, 0);

複製代碼

那麼爲何要這麼作呢?

固然是爲了和瀏覽器更加趨同。日誌

瞭解瀏覽器的eventloop可能就知道,瀏覽器的宏任務隊列執行了一個,就會執行微任務。

簡單的說,能夠把瀏覽器的宏任務和node10的timers比較,就是node10只有所有執行了timers階段隊列的所有任務才執行微任務隊列,而瀏覽器只要執行了一個宏任務就會執行微任務隊列。

如今node11在timer階段的setTimeout,setInterval...和在check階段的immediate都在node11裏面都修改成一旦執行一個階段裏的一個任務就馬上執行微任務隊列。

最後

因此在生產環境建議仍是不要特地的去利用node和瀏覽器不一樣的一些特性。即便是node和瀏覽器相同的特性,但規範沒肯定的一些特性,也建議當心使用。不然一次小小的node升級可能就會形成一次線上事故,而不僅是啪啪打臉這麼簡單了。

相關文章
相關標籤/搜索