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