目錄
- 事件回圈機制
- 同步與異步
- 微任務與宏任務(異步事件)
- 任務執行順序
- 最終總結
事件回圈機制
同步與異步
我們先思考兩個問題,如下:
為什么會存在同步和異步的概念?
我們的JavaScript是單執行緒的,也就是我們的作業流水線的只有一條,如果我們的任務全放在流水線上,其中一個任務出現問題就會阻塞后面的任務,導致我們的作業流水線卡住,因此為了更加高效合理利用這條流水線,在JavaScript中出現了同步與異步的概念,
同步與異步任務如何在一條流水線上作業?
同樣是一條流水線,我們的有不同的產品,有的產品能瞬間完成,有的產品需要耗費大量時間才能完成,那么我們給這堆產品分為兩類,能瞬間完成的產品先放入流水線前面,而需要耗費大量時間的產品則放在流水線后面,將所有的產品按順序從流水線上執行,即使后面有部分產品制作很慢,但我們流水線前面的大部分產品都能順利完成,也就是說,我們能夠及時交付大部分的產品,讓老板基本滿意就足夠了,后面的產品我們再慢慢做也不遲,
同步
同步任務:我們的任務不會造成流水線阻塞,瞬間就能完成,那我們直接把這些任務定義為同步任務,
同步事件:new Promise()、async關鍵字、console物件方法
異步
異步任務:我們的任務可能會造成流水線阻塞,需要時間才能完成,那我們直接把這些任務定義為異步任務,
異步事件:我們先不介紹異步事件,因為異步事件又分為微任務與宏任務,我們下面再介紹,
微任務與宏任務(異步事件)
微任務事件:Promise.then()、await 后面的陳述句、queueMiscrotask、MutationObserver、process.nextTick( node.js環境 )[ 微任務中最先執行 ]
宏任務事件:setTimout() 和 setInterval()、<script>腳本、I/O、UI互動事件、setImmediate( node.js環境 )[ 宏任務中最后執行 ]
注意:異步事件分為微任務和宏任務,其中微任務優先于宏任務執行,
任務執行順序
執行堆疊:同步代碼會首先歸類到此處待執行,按照代碼的書寫順序(上到下)入堆疊,
微任務佇列:異步中的微任務代碼歸類到此處,按照代碼的書寫順序(上到下)入隊,當執行堆疊為空時,微任務會出隊進入執行堆疊,
宏任務佇列:異步中的宏任務代碼歸類到此處,按照代碼的書寫順序(上到下)入隊,當微任務佇列為空時,宏任務會出隊進入執行堆疊,
我們采用驗證法做幾道題
第一道如下:
console.log(1)
setTimeout(() => {
console.log(2)
setTimeout(() => {
console.log(3)
}, 1000)
}, 1000)
new Promise((resolve, reject) => {
console.log(4)
resolve(5) // 之后會呼叫 then 方法
console.log(6)
}).then((resolve, reject) => {
console.log(resolve)
})
function add(a, b) {
return a + b
}
async function foo() {
console.log(7)
let num = await add(4, 4)
console.log(9)
return num
}
foo().then((num) => {
console.log(num)
})
console.log(10) // 1 4 6 7 10 5 9 8 2 3
以上代碼沒有出現宏任務嵌套微任務,微任務嵌套宏任務的情況,那么我們可以按編號(對應的輸出陳述句)直接對執行堆疊、微任務和宏任務分類如下:
第一次分析執行堆疊(同步任務):1 4 6 7 10
第二次分析微任務:5 9 8
第三次分析宏任務:2 3
然后我們按執行順序將答案組合在一起,最終答案:1 4 6 7 10 5 9 8 2 3,
注意:以上分析方法只能應對異步函式無嵌套的情況,
接下來我們增加難度,宏任務嵌套微任務,微任務嵌套宏任務,第二題如下:
console.log(1)
setTimeout(() => {
console.log(2)
new Promise((resolve, reject) => {
console.log(3)
resolve(4)
}).then((resolve, reject) => {
console.log(resolve)
})
console.log(5)
}, 1000)
console.log(6)
new Promise((resolve, reject) => {
console.log(7)
resolve(8)
setTimeout(() => {
console.log(9)
}, 1000)
}).then((resolve, reject) => {
console.log(resolve)
})
console.log(10) // 1 6 7 10 8 2 3 5 4 9
以上代碼出現了宏任務嵌套微任務,微任務嵌套宏任務的情況,
提示:外部(全域作用域)的代碼可以按任務執行順序分析,異步函式內部其實也可以按照我們的任務執行順序分析,其分析程序是一樣的,
最終答案:1 6 7 10 8 2 3 5 4 9,還有很多特例,可自行撰寫異步函式測驗,總結方法
最終總結
分析方法:先對代碼進行事件分類,然后分別放入對應型別的三個地方(執行堆疊、微任務佇列和宏任務佇列)再按照我們的執行順序,發生異步函式嵌套情況時,也可以對其內部應用這套規則解決,
任務執行順序如下:
- 同步(new Promise()、async關鍵字、console物件方法)
- process.nextTick(node.js環境)
- 微任務(異步)(Promise().then()、await 后面的陳述句)
- 宏任務(異步)(定時器函式、<script>腳本、I/O、UI互動事件)
- setImmediate(node.js環境)(當前事件回圈結束后執行)
參考
【前端八股文】事件回圈-宏任務和微任務
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/542051.html
標籤:其他
