思思放出一道題目,深究一下發覺頗有意思
<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