前端读者 | 由setTimeout引发的JS引擎运行机制的研究
本文來自 @xiaoyuze88 鏈接:http://xiaoyuze88.github.io/
太久沒碰代碼了,那天想到關(guān)于循環(huán)調(diào)用setTimeout實現(xiàn)每隔一秒輸出遞增的數(shù)的那個問題,搞了搞,發(fā)現(xiàn)很多概念模糊了,在此總結(jié)下。
所謂的循環(huán)調(diào)用setTimeout實現(xiàn)遞增輸出,就是說用for循環(huán)10次,每隔一秒輸出一個從0~9的數(shù)。
不多說,直接上最終代碼再說,細(xì)節(jié)后面再談。
for (var i = 0; i < 10; i++) {//這里用閉包,為每一個i生成一個獨(dú)立的上下文環(huán)境,傳遞給里面的console.log,而不會受到setTimeout延時而影響(function (i) {`setTimeout`(function () {console.log(i);}, 1000 * i)})(i); }這里主要的問題在:
首先閉包,這里就不多說了,在這里,閉包的作用就是給閉包內(nèi)的函數(shù)生成一個不受外面環(huán)境干擾的上下文環(huán)境,由于js的作用域問題。
如果這里不用閉包,寫成諸如:
for (var i = 0; i < 10; i++) {`setTimeout`(function () {console.log(i);}, i * 1000); }會發(fā)現(xiàn),每隔一秒鐘,輸出一個10。
這是由于這一個for循環(huán)的執(zhí)行,瞬間就完成了,也就是說,瞬間注冊了10個延時執(zhí)行的函數(shù),每一個隔一秒鐘執(zhí)行。
當(dāng)注冊的時間點(diǎn)到來,開始執(zhí)行setTimeout中的語句,由于定義域的問題,此時console.log(i)的這個i指向的是已經(jīng)到達(dá)10的for循環(huán)中的i,這就是為什么要用閉包來給setTimeout設(shè)置獨(dú)立的上下文環(huán)境,而避免需要訪問i時訪問到了外面的變量。
另外,如果細(xì)想一下,會發(fā)現(xiàn)setTimeout的工作過程多少讓人有點(diǎn)迷惑,到底setTimeout等延時類函數(shù)在瀏覽器中是如何運(yùn)作的?這就牽扯到下一個問題,關(guān)于瀏覽器中是如果運(yùn)作的問題。
瀏覽器中,JS引擎是單線程的,假設(shè)一個瀏覽器中有三個常駐線程,既JS引擎線程、渲染線程、事件觸發(fā)線程,還有處理完即結(jié)束的線程如AJAX異步請求。
其中,JS線程與渲染線程是互斥的,這是為了避免JS控制DOM時與頁面渲染發(fā)生沖突。而對于JS線程,它是由事件驅(qū)動的,由于單線程,所有任務(wù)依隊列排序。如果頁面上觸發(fā)了事件,如onclick=function(){}、或者由setTimeout添加了一個函數(shù)、ajax請求返回的事件等,所有新添加的任務(wù)位于隊尾等待處理。
由于是單線程,如果線程被阻塞,如while(true){}死循環(huán),則一切新添加的任務(wù)都將被阻塞。
由上面所述,就可以理解為什么setTimeout或setInterval設(shè)置的延時事件并不是真是函數(shù)處理的延時時間,既setTimout(code,1000)并不是一定會在1秒后處理,這段代碼發(fā)生的僅僅是在1秒后,將待處理函數(shù)排與js任務(wù)隊列末尾。
轉(zhuǎn)載于:https://www.cnblogs.com/chenrf/p/10106433.html
總結(jié)
以上是生活随笔為你收集整理的前端读者 | 由setTimeout引发的JS引擎运行机制的研究的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 用django2.1开发公司官网(上)
- 下一篇: selenium基础框架的封装(Pyth