什么是事件回圈?想要了解什么是事件回圈就要從js的作業原理開始說起:
JS主要的特點就是單執行緒,所謂單執行緒就是行程中只有一個執行緒在運行,
為什么JS是單執行緒的而不是多執行緒的呢?
JS的主要用途就是與用戶互動,操作DOM,假設JS同時有兩個執行緒,一個執行緒中在某個DOM節點上添加或者修改內容,而另一個執行緒在這個DOM節點上執行洗掉該節點操作,這樣就會產生沖突,
單執行緒就意味著所有任務都需要排隊,前一任務結束,才會執行后一個任務,當是如果當遇到前一個任務耗時很長的情況,后一個任務就不得不一直等著,因此,就有了同步任務、異步任務,
同步任務和異步任務在js中是如何執行的呢?
js的代碼運行會形成一個主執行緒和一個任務佇列,主執行緒會自上而下依次執行我們的js代碼,形成一個執行堆疊,
同步任務就會被放到這個主執行緒中依次執行,而異步任務被放入到任務佇列中執行,執行完就會在任務佇列中打一個標記,形成一個對應的事件,當主執行緒中的任務全部運行完畢,js會去提取并執行任務佇列中的事件,這個程序是回圈進行的,這就是EventLoop,
JS引擎執行異步代碼不用等待,是因為有事件佇列和事件回圈,
事件回圈是指主執行緒重復從事件佇列中取訊息、執行的程序,指整個執行流程,
事件佇列是一個存盤著待執行任務的序列,其中的任務嚴格按照時間先后順序執行,排在隊頭的任務會率先執行,而排在隊尾的任務會最后執行,(即先進先出)

事件佇列:
- 一個執行緒中,事件回圈是唯一的,但是任務佇列可以有多個;
- 任務佇列又分macro-task(宏任務)和micro-task(微任務);
- macro-task包括:script(整體代碼)、setTimeout、setInterval、setImmediate、I/O、UI rendering;
- micro-task包括:process.nextTick, Promise, Object.observe(已廢棄), MutationObserver(html5新特性)
- setTimeout/Promise等稱為任務源,而進入任務佇列的是他們制定的具體執行任務;來自不同任務源的任務會進入到不同的任務佇列,其中setTimeout與setInterval是同源的,
事件回圈運行機制
(1)執行一個宏任務(堆疊中沒有就從事件佇列中獲取)
(2)執行程序中如果遇到微任務,就將它添加到微任務的任務佇列中;
(3)宏任務執行完畢后,立即執行當前微任務佇列的所有微任務;
(4)當前微任務執行完畢,開始檢查渲染,然后GUI執行緒接管渲染;
(5)渲染完畢后,JS執行緒繼續接管,開始下一個宏任務,

事例:
async function async1() {
console.log("async1 start"); //(2)
await async2();
console.log("async1 end"); //(6)
}
async function async2() {
console.log( 'async2'); //(3)
}
console.log("script start"); //(1)
setTimeout(function () {
console.log("settimeout"); //(8)
},0);
async1();
new Promise(function (resolve) {
console.log("promise1"); //(4)
resolve();
}).then(function () {
console.log("promise2"); //(7)
});
console.log('script end');//(5)
按照事件回圈機制分析以上代碼運行流程:
1. 首先,事件回圈從宏任務(macrotask)佇列開始,首先讀取script(整體代碼)任務;當遇到任務源(task source)時,則會先分發任務到對應的任務佇列中去,
2. 然后我們看到首先定義了兩個async函式,此時沒有呼叫,接著往下看,然后遇到了 `console` 陳述句,直接輸出 `script start`,輸出之后,script 任務繼續往下執行,遇到 `setTimeout`,其作為一個宏任務源,則會先將其任務分發到對應的任務佇列中,
3. script 任務繼續往下執行,執行了async1()函式,async函式中在await之前的代碼是立即執行的,所以會立即輸出`async1 start`,
遇到了await時,會將await后面的運算式執行一遍,所以就緊接著輸出`async2`,然后將await后面的代碼也就是`console.log('async1 end')`加入到microtask中的Promise佇列中,接著跳出async1函式來執行后面的代碼,
4. script任務繼續往下執行,遇到Promise實體,由于Promise中的函式是立即執行的,而后續的 `.then` 則會被分發到 microtask 的 `Promise` 佇列中去,所以會先輸出 `promise1`,然后執行 `resolve`,將 `promise2` 分配到對應佇列,
5. script任務繼續往下執行,輸出了 `script end`,至此,全域任務就執行完畢了,
根據上述,每次執行完一個宏任務之后,會去檢查是否存在 Microtasks;如果有,則執行 Microtasks 直至清空 Microtask Queue,
因而在script任務執行完畢之后,開始查找清空微任務佇列,此時,微任務中, `Promise` 佇列有的兩個任務`async1 end`和`promise2`,因此按事件佇列先進先出的原則,先后順序輸出 `async1 end,promise2`,當所有的 Microtasks 執行完畢之后,表示第一輪的回圈就結束了,
6. 第二輪回圈依舊從宏任務佇列開始,此時宏任務中只有一個 `setTimeout`,取出直接輸出即可,至此整個流程結束,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/260176.html
標籤:其他
上一篇:vue中怎么動態生成form表單
