setTimeout 在 js 加載前的問題探究

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
相關文章
相關標籤/搜索