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