摘要:在第一次循環的時候并沒有被賦值,所以是,在第二次循環的時候,定時器其實清理的是上一個循環的定時器。所以導致每次循環都是清理上一次的定時器,而最后一次循環的定時器沒被清理,導致一直輸出。
Javascript Evet Loop 模型
setTimeout()最短的事件間隔是4ms
setInterval()最短的事件間隔是10ms
以上這個理論反正我是沒有驗證過
console.log("start"); const interval = setInterval(() => { console.log("setInterval"); }, 0); setTimeout(() => { console.log("setTimeout 1"); Promise.resolve() .then(() => { console.log("promise 3"); }) .then(() => { console.log("promise 4"); }) .then(() => { setTimeout(() => { console.log("setTimeout 2"); Promise.resolve() .then(() => { console.log("promise 5"); }) .then(() => { console.log("promise 6"); }) .then(() => { clearInterval(interval); }); }, 0); }); }, 0); Promise.resolve() .then(() => { console.log("promise 1"); }) .then(() => { console.log("promise 2"); });------非chrome result:------
start promise 1 promise 2 setInterval setTimeout 1 promise 3 promise 4 setInterval setTimeout 2 promise 5 promise 6------node.js result------
start promise 1 promise 2 setInterval setTimeout 1 promise 3 promise 4 setInterval setTimeout 2 setInterval promise 5 promise 6------windows/mac chrome result:------
start promise 1 promise 2 setInterval setTimeout 1 promise 3 promise 4 setInterval setInterval setTimeout 2 promise 5 promise 6
在windows chrome里setTimeout 2上方會出現連續兩個setInterval,有些奇怪,在mac的chrome和windows的firefox都是正常的輸出(發生錯誤的window chrome版本號為:Version 65.0.3325.181 (Official Build) (64-bit))
經過更多次測試,關于上述結論做如下更正:
windows/mac chrome 運行這段代碼有時會出現雙setInterval情況,而另一些時候則和非chrome瀏覽器環境運行無異。這種情況筆者暫時還沒有找到準確的答案。
console.log("start"); var nerdPointer; function nerdFunc(){ console.log("setInterval"); nerdPointer = setTimeout(nerdFunc,0); } setTimeout(nerdFunc,0); setTimeout(() => { console.log("setTimeout 1"); Promise.resolve() .then(() => { console.log("promise 3"); }) .then(() => { console.log("promise 4"); }) .then(() => { setTimeout(() => { console.log("setTimeout 2"); Promise.resolve() .then(() => { console.log("promise 5"); }) .then(() => { console.log("promise 6"); }) .then(() => { clearInterval(nerdPointer); }); }, 0); }); }, 0); Promise.resolve() .then(() => { console.log("promise 1") }) .then(() => { console.log("promise 2") });
windows chrome下跑上面這段代碼并不會出錯
Exemple 2 ------question:------function expendTime(k){ console.log((new Date()).getTime()); while(k < 1000){ for(var j = 2; j < k; j++){ if(k%j == 0){ break; } if(j == k-1){ console.log(k) } } k++; } console.log((new Date()).getTime()); clearInterval(t); } var t = setInterval(expendTime,15,3);------result:------
結果:只進行了一次expendTime()計算
mac 17對于expendTime()的運行事件大概在30ms朝上,setInterval()設定的間隔是15ms,所以在expendTime()沒有執行完畢的時候并沒有再添加一個expendTime()到task queue中(函數結尾setInterval()被清除),所以結果才只進行了一次expendTime()的計算
Example 3將Example 2中的代碼做如下修改,再次進行測試
------question:------function expendTime(k){ console.log((new Date()).getTime()); while(k < 10000){ for(var j = 2; j < k; j++){ if(k%j == 0){ break; } if(j == k-1){ console.log(k) } } k++; } console.log((new Date()).getTime()); } var t = setInterval(expendTime,15,3); setTimeout(function (){clearInterval(t);},30);------chrome result:------
輸出了兩次后被停止
------非chrome result:------輸出一次后停止,證明在大多數瀏覽器上,Exemple 2中的結論是正確的
------conclusion:------又是在chrome上出現了不合理的詭異的行為。和標準中event loop的理論相悖
Example 4 ------question:------function fn1() { for (var i = 0; i < 4; i++) { var tc = setTimeout(function(i) { console.log(i); clearTimeout(tc) }, 10, i); } } function fn2() { for (var i = 0; i < 4; i++) { var tc = setInterval(function(i, tc) { console.log(i); clearInterval(tc) }, 10, i, tc); } } fn1(); fn2();------answer:------
這題考察了對閉包和定時器另外還有js執行順序的理解。
先來說說fn1,如果把clearTimeout去掉,相信大家一定很熟悉,都會說10ms延遲后會依次輸出0,1,2,3。
但是,請注意這里加了個clearTimeout,如果你去控制臺實驗的話會發現只輸出了0,1,2,那3呢?
先別急,請聽我慢慢道來:
請注意:這個tc是定義在閉包外面的,也就是說tc并沒有被閉包保存,所以這里的tc指的是最后一個循環留下來的tc,所以最后一個3被清除了,沒有輸出。
再來看看fn2,可以發現區別就是把setTimeout改為了setInterval,同時把定時器也傳到了閉包里。
那么結果又會有什么不同呢?如果親自去實驗的同學就會發現輸出0,1,2,3,3,3...。
什么鬼?為毛最后一個定時器沒被刪除。說實話,我在這里也想了很久,為何最后一個定時器沒被刪除。后來我為了調試方便把i<4改為了i<2并把觸發時間改為3s,在瀏覽器中單步調試,發現3s后第一次觸發回調函數執行的時候tc的值是undefined第二次觸發的時候有值了。這個時候我頓悟,這和程序的執行順序有關。我們知道js正常情況下是從上到下,從右到左執行的。
所以這里每次循環先設置定時器,然后把定時器的返回值賦值給tc。在第一次循環的時候tc并沒有被賦值,所以是undefined,在第二次循環的時候,定時器其實清理的是上一個循環的定時器。所以導致每次循環都是清理上一次的定時器,而最后一次循環的定時器沒被清理,導致一直輸出3。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/107683.html
摘要:概述本文主要介紹了我對的一些核心特性的理解,包括架構特點機制核心模塊與簡單應用。在此期間,主線程繼續執行其他任務。延續了瀏覽器端單線程,只用一個主線程執行,不斷循環遍歷事件隊列,執行事件。 原文地址在我的博客,轉載請注明來源,謝謝! node是在前端領域經常看到的詞。node對于前端的重要性已經不言而喻,掌握node也是作為合格的前端工程師一項基本功了。知道node、知道后端的一些東西...
摘要:如果看完本文后,還對進程線程傻傻分不清,不清楚瀏覽器多進程瀏覽器內核多線程單線程運行機制的區別。因此準備梳理這塊知識點,結合已有的認知,基于網上的大量參考資料,從瀏覽器多進程到單線程,將引擎的運行機制系統的梳理一遍。 前言 見解有限,如有描述不當之處,請幫忙及時指出,如有錯誤,會及時修正。 ----------超長文+多圖預警,需要花費不少時間。---------- 如果看完本文后,還...
摘要:關于這部分有嚴格的文字定義,但本文的目的是用最小的學習成本徹底弄懂執行機制,所以同步和異步任務分別進入不同的執行場所,同步的進入主線程,異步的進入并注冊函數。宏任務微任務第三輪事件循環宏任務執行結束,執行兩個微任務和。 不論你是javascript新手還是老鳥,不論是面試求職,還是日常開發工作,我們經常會遇到這樣的情況:給定的幾行代碼,我們需要知道其輸出內容和順序。 因為javascr...
摘要:事件完成,回調函數進入。主線程從讀取回調函數并執行。終于執行完了,終于從進入了主線程執行。遇到,立即執行。宏任務微任務第三輪事件循環宏任務執行結束,執行兩個微任務和。事件循環事件循環是實現異步的一種方法,也是的執行機制。 本文的目的就是要保證你徹底弄懂javascript的執行機制,如果讀完本文還不懂,可以揍我。不論你是javascript新手還是老鳥,不論是面試求職,還是日常開發工作...
閱讀 3976·2021-11-23 10:09
閱讀 1344·2021-11-23 09:51
閱讀 2944·2021-11-23 09:51
閱讀 1590·2021-09-07 09:59
閱讀 2357·2019-08-30 15:55
閱讀 2300·2019-08-30 15:55
閱讀 2952·2019-08-30 15:52
閱讀 2565·2019-08-26 17:04