前置知識點
- 首先,JS是單線程的,同一時間只會執(zhí)行一段JS代碼。
- 不過,瀏覽器是多線程的,但這也不意味著可以模擬JS的多線程。
- 瀏覽器中至少有3個常駐線程:
- JS引擎(執(zhí)行JS代碼)
- GUI渲染線程:當界面需要重繪(Repaint)或由于某種操作引發(fā)回流(Reflow)時,GUI線程就會執(zhí)行。
補充:JS引擎和GUI渲染線程是互斥的,當JavaScript引擎執(zhí)行時GUI線程會被掛起,GUI更新會被保存在一個隊列中等到JavaScript引擎空閑時立即被執(zhí)行。
- 瀏覽器事件觸發(fā)線程:當一個事件被觸發(fā)時該線程會把事件添加到待處理隊列的隊尾,等待JavaScript引擎的處理。
- 這些事件可來自JavaScript引擎當前執(zhí)行的代碼塊如setTimeout、也可來自瀏覽器內(nèi)核的其他線程如鼠標點擊、Ajax異步請求等
- 事件循環(huán)模型: 每次有事件發(fā)生時,事件觸發(fā)線程將事件放入任務隊列,等到執(zhí)行引擎在主線程方法(也可以說是同步任務)執(zhí)行完畢,到達空閑狀態(tài)時,會從任務隊列中順序獲取任務來執(zhí)行(這里的是異步任務),這一過程是一個不斷循環(huán)的過程,稱為事件循環(huán)模型。
setTimeout(fn,xx)
- 當在主體代碼中執(zhí)行到setTimeout函數(shù)時,瀏覽器會開啟一個定時器線程,當過了指定的時間間隔以后,會向任務隊列插入任務,即使間隔時間設置為0,也還是要放入任務隊列,等待所有主體任務完成以后,執(zhí)行線程再從任務隊列中取出任務來執(zhí)行。
setInterval(fn,xx)
- 大致部分同上,只是有一點需要注意,有時候會因主體部分代碼執(zhí)行占用了處理器時間,導致事件線程第n次向任務隊列插入任務時,第n-1次的任務還沒被執(zhí)行,此時會放棄第n次插入。
- 因為js有規(guī)定:
為了確保定時器代碼插入到隊列總的最小間隔為指定時間。當使用setInterval()時,僅當沒有該定時器的任何其他代碼實例時,才能將定時器代碼添加到代碼隊列中。
- 因為js有規(guī)定: