對於script標籤中的全部同步代碼,總體能夠當作一個宏任務。promise
宏任務,macrotask,也叫tasks。 一些==異步任務的回調==會依次進入macro task queue,等待後續被調用,這些異步任務包括:瀏覽器
setTimeoutmarkdown
setInterval異步
setImmediate (Node獨有)函數
requestAnimationFrame (瀏覽器獨有)oop
I/Ospa
UI rendering (瀏覽器獨有).net
微任務,microtask,也叫jobs。 另外一些==異步任務的回調==會依次進入micro task queue,等待後續被調用,這些異步任務包括:插件
注意:Promise構造函數裏的代碼是同步執行的,而Promise.then()是異步的。code
組成:一個函數執行棧stack、一個事件隊列Task Queue(可看做宏任務隊列)、一個微任務隊列Microtask Queue。
一輪事件循環:每次從事件隊列中取出一個事件(每次從宏任務隊列中取出一個宏任務)放入函數執行棧執行,執行完畢後緊接着把此時微任務事件隊列中的微任務事件一個一個所有取出並執行。
而後,在取出宏任務事件隊列中的下一個宏任務並執行,執行完畢後緊接着把此時微任務事件隊列中的微任務事件一個一個所有取出並執行。.......如此往復循環。
來個基礎題加深理解:
例1:
setTimeout(()=> {
console.log(1)
Promise.resolve(3).then(data => console.log(data))
}, 0)
setTimeout(()=> {
console.log(2)
}, 0)
複製代碼
首先,第1行的setTimeout函數是宏任務1,第5行的setTimeout函數是宏任務2。第3行的promise.then()函數是微任務1。
執行過程爲:
宏任務1(第一個setTimeout函數)進入函數執行棧並執行,輸出1,宏任務1執行完畢執行此時微任務隊列中的微任務1進入函數執行棧並執行,輸出3;接着,宏任務2進入函數執行棧並執行,輸出2 。因此,輸出順序爲 1 ,3 ,2。
小tip: 這個例子中
第一輪事件循環:將宏任務0(script函數)放入函數執行棧執行,此時微任務事件隊列爲空;(若在瀏覽器控制檯寫代碼,沒有返回值時,瀏覽器會自動返回一個返回值,此返回值與插件相關,不用深究)
第二輪事件循環:宏任務1(第一個setTimeout函數)進入函數執行棧並執行,輸出1,宏任務1執行完畢執行此時微任務隊列中的微任務1(Promise.then()函數)進入函數執行棧並執行,輸出3;
第三輪事件循環:宏任務2(第二個setTimeout函數)進入函數執行棧並執行,輸出2,此時微任務事件隊列爲空;
例2:
console.log("script start")
setTimeout(function () {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function () {
console.log('promise1');
}).then(function () {
console.log('promise2');
});
// script start
// promise1
// promise2
// setTimeout
複製代碼