event loop

前言

最近一直在看基本知識點,發(fā)現(xiàn)自己的理解太過于偏頗、淺顯加之記憶力不行,遂還是以文字的形式記錄下來,這是緣由之一。當然,也希望通過這樣的方式去整理邏輯,使之清晰。

為什么會有event loop?

和其他語言相比較,JavaScript語言特點就是單線程的。起初這門語言的設(shè)計主要用于與用戶互動的,提高用戶網(wǎng)頁使用的體驗度。然后漸漸發(fā)展成前端開發(fā)必不可少的語言。但是在實際的業(yè)務當中,開發(fā)人員發(fā)現(xiàn)單線程有太多的阻礙。這也是event loop產(chǎn)生的原因。

什么是event loop

主線程從“任務隊列”中讀取事件,這個過程是循環(huán)不斷的,所以整個的這種運行機制成為even loop。

運行進制

首先需要了解JavaScript的運行機制

  1. 所有同步任務都在主線程上執(zhí)行,形成一個執(zhí)行棧。
  2. 主線程之外,還存在“任務隊列”。只要異步任務有了運行結(jié)果,就在“任務隊列”之中放置一個事件。
  3. 一旦“執(zhí)行?!敝械乃型饺蝿請?zhí)行完畢,系統(tǒng)就會讀取“任務隊列”,看看里面有哪些事件。那些對應的異步任務,于是接收等待狀態(tài),進入執(zhí)行棧,開始執(zhí)行。
  4. 主線任務不斷重復上面的第三步。

再說even loop 運行進制。
主線任務會不斷從任務隊列中按順序去取任務執(zhí)行,每執(zhí)行完一個任務都會檢查microtask隊列是否為空,如果不為空則會一次性執(zhí)行完所有的microtask。然后再進入下一個循環(huán)去任務隊列中去下一個任務執(zhí)行。

具體如下:

  1. 當選擇需要執(zhí)行的宏任務隊列,選擇一個最先進入任務隊列的宏任務,如果沒有宏任務選擇,則會跳轉(zhuǎn)至microtask的執(zhí)行步驟。
  2. 將事件循環(huán)的當前運行宏任務設(shè)置為已選擇的宏任務。
  3. 運行宏任務。
  4. 將事件循環(huán)的當前運行任務設(shè)置為null。
  5. 將運行完的宏任務從宏任務隊列中移除。
  6. microtask步驟:進入microtask檢查點。
  7. 更新界面渲染。
  8. 返回第一步

執(zhí)行進入microtask 檢查的具體步驟:

  1. 設(shè)置進入microtask檢查點的標志位true
  2. 當事件循環(huán)的微任務隊列不為空時,選擇一個最先進入microtask隊列的microtask;設(shè)置事件循環(huán)的當前運行任務為null,將運行結(jié)束的microtask從microtask隊列中移除。
  3. 對于相應事件循環(huán)的每個環(huán)境設(shè)置對象,通知他們哪些promise為rejected.
  4. 清理indexDB的事務。
  5. 設(shè)置進入microtask檢查點的標志為false。
console.log('script start')

setTimeout(function(){
    console.log('setTimeout --- 0')
},0)

setTimeout(function(){
    console.log('setTimeout --- 200')
    setTimeout(function(){
        console.log('inner -setTimeout --- 0')
    })
    Promise.resolve().then(function(){
        console.log('promise5')
    })
},200)

Promise.resolve().then(function(){
    console.log('promise1')
}).then(function(){
    console.log('promise2')
})

Promise.resolve().then(function(){
    console.log('promise3')
})
console.log('script end')

運行結(jié)果:
script start

script end
promise1
promise3
promise2
setTimeout --- 0
setTimeout --- 200
promise5
inner -setTimeout --- 0

分析:

  1. 首先順序執(zhí)行完主進程上的同步任務,第一句和最后一句的console.log
  2. 接著遇到setTimeout 0,它的作用是在 0ms 后將回調(diào)函數(shù)放到宏任務隊列中(這個任務在下一次的事件循環(huán)中執(zhí)行)。
  3. 接著遇到setTimeout 200,它的作用是在 200ms 后將回調(diào)函數(shù)放到宏任務隊列中(這個任務在再下一次的事件循環(huán)中執(zhí)行)。
  4. 同步任務執(zhí)行完之后,首先檢查微任務隊列, 即 microtask隊列,發(fā)現(xiàn)此隊列不為空,執(zhí)行第一個promise的then回調(diào),輸出 'promise1',然后執(zhí)行第二個promise的then回調(diào),輸出'promise3',由于第一個promise的.then()的返回依然是promise,所以第二個.then()會放到microtask隊列繼續(xù)執(zhí)行,輸出 'promise2';
    5.此時microtask隊列為空,進入下一個事件循環(huán), 檢查宏任務隊列,發(fā)現(xiàn)有 setTimeout的回調(diào)函數(shù),立即執(zhí)行回調(diào)函數(shù)輸出 'setTimeout---0',檢查microtask 隊列,隊列為空,進入下一次事件循環(huán).
  5. 檢查宏任務隊列,發(fā)現(xiàn)有 setTimeout的回調(diào)函數(shù), 立即執(zhí)行回調(diào)函數(shù)輸出'setTimeout---200'
  6. 接著遇到setTimeout 0,它的作用是在 0ms 后將回調(diào)函數(shù)放到宏任務隊列中,檢查微任務隊列,即 microtask 隊列,發(fā)現(xiàn)此隊列不為空,執(zhí)行promise的then回調(diào),輸出'promise5'。
  7. 此時microtask隊列為空,進入下一個事件循環(huán),檢查宏任務隊列,發(fā)現(xiàn)有 setTimeout 的回調(diào)函數(shù),立即執(zhí)行回調(diào)函數(shù)輸出,輸出'inner-setTimeout---0'。代碼執(zhí)行結(jié)束。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

  • 前言 本文我們將會介紹 JS 實現(xiàn)異步的原理,并且了解了在瀏覽器和 Node 中 Event Loop 其實是不相...
    浪里行舟閱讀 1,479評論 2 10
  • JS中比較讓人頭疼的問題之一要算異步事件了,比如我們經(jīng)常要等后臺返回數(shù)據(jù)后進行dom操作,又比如我們要設(shè)置一個定時...
    si_月閱讀 1,085評論 0 0
  • 什么是事件循環(huán)(Event Loop) 事件循環(huán)能讓 Node.js 執(zhí)行非阻塞 I/O 操作,盡管JavaScr...
    假面猿閱讀 827評論 0 0
  • 前言 Event Loop即事件循環(huán),是指瀏覽器或Node的一種解決javaScript單線程運行時不會阻塞的一種...
    六月繁花開閱讀 520評論 0 3
  • 哈哈,終于 明天放假啦。一定要睡個懶覺 梵音瑜伽 專業(yè)16年 你值得擁有
    _骨頭閱讀 81評論 1 1

友情鏈接更多精彩內(nèi)容