1. 程式人生 > >setTimeout 在 js 加載前的問題探究

setTimeout 在 js 加載前的問題探究

fir 1.10 out 答案 ref article 而且 plugins html

setTimeout 在 js 加載前的問題探究

思思放出一道題目,深究一下發覺很有意思
<script>
  setTimeout(() => {
    alert(‘2‘);
  }, 0)</script>
<script src="https://test.tms-uat.xuebangsoft.net/plugins/jquery-1.10.2.min.js"></script>
<script>
  alert(‘1‘)
</script>
眾所周知, setTimeout 會進入事件循環,等待主線程空閑時才運行。 所以理論上來看,肯定都會先彈 1 再彈 2。 而當我 shift+F5 強刷時(或小概率),是先彈 2 的,後續直接 F5 還是先彈 1。 而如果將中間的 js 加載去掉,也不會先彈 2, 假如,setTimeout 前面也加上 js 加載,也不會先彈 2。 可見,此處好像 js 加載產生了一點微妙的化學反應。 後來通過 chrome 的 Performance 面板進行性能分析, 發現兩種情況下的代碼先後順序是不同的: 先彈 2 時的代碼順序: 技術分享圖片
先彈 1 時的代碼順序: 技術分享圖片 此時答案就比較明顯了: 先彈 2 是由於 js 加載阻斷了後面 alert 代碼的運行, 而使得主線程還未有代碼,因此 setTimeout 立馬循環到而先跑完了; 而先彈 1 則是 js 已被緩存,後續代碼立馬進入主線程,setTimeout 在事件循環中就靠後了。 雖然實操中不太可能會遇到這樣的使用場景, 但對瀏覽器的運行規則又有了一些別樣的眼光。
在試驗中,會更換多個瀏覽器查看,結果發現另一個有趣的現象: 各瀏覽器對事件循環的處理好像並不標準呢,而且 ajax 在 chrome 竟然也是和 Promise 一樣的微循環喲。
setTimeout(function(){
 alert(1)
}, 0);

for (var i=0; i<1e8; i++) {}
new Promise((resolve) => {
 resolve();
}).then(function(){
 alert(2);
});

for (var i=0; i<1e8; i++) {}
requestAnimationFrame(function(){
 alert(3);
});

for (var i=0; i<1e8; i++) {}
$.get(‘./list.html‘, function(){
 alert(4);
});

for (var i=0; i<1e8; i++) {}
alert(5);

// chrome 結果 5 2 3 4 1
// firefox 結果 5 4 2 1 3

setTimeout 在 js 加載前的問題探究