一、任務隊列的概念
任務隊列是JavaScript中實現異步編程的重要機制。在任務隊列中,任務被分為兩種類型:微任務和宏任務。在理解微任務和宏任務的區別之前,我們需要先了解任務隊列的概念。
//偽代碼
setTimeout(() => {
console.log('task1');
}, 0);
Promise.resolve().then(() => {
console.log('task2');
});
console.log('task3');
在上述代碼中,我們可以看到三個任務:task1、task2和task3。但是,它們並不是同步執行的,而是按照任務隊列中的順序依次被加入隊列中。即task1首先被加入隊列,在等待指定的時間後執行;task2作為微任務先被加入隊列,在當前執行棧執行完成後執行;task3被加入隊列,等待之前的任務執行完成後執行。
二、微任務和宏任務的區別
相較於宏任務,微任務是一類運行時機更加早的任務。
1. 執行時機不同
當後台任務隊列的執行棧為空時,JavaScript引擎會從任務隊列中取出一個任務並執行。每當一個任務執行結束,引擎就會檢查是否需要執行微任務隊列中的任務。只有在當前宏任務執行結束後才會執行微任務的隊列。
//偽代碼
console.log('task1');
setTimeout(() => {
console.log('task2');
}, 2000);
Promise.resolve().then(() => {
console.log('task3');
});
console.log('task4');
在上面的代碼中,task1和task4是宏任務,其中task2是在2秒鐘後被執行的宏任務,task3是在當前Promise執行完成後被執行的微任務。代碼的執行順序是:task1->task4->task3->task2。
2. 存儲方式不同
宏任務的存儲方式是一個個保存在任務隊列中的,而微任務不同,它們是存在於宏任務中的,也就是說每個宏任務都有一個微任務隊列。
//偽代碼
setTimeout(() => {
console.log('task1');
Promise.resolve().then(() => {
console.log('task2');
});
}, 0);
console.log('task3');
在上面的代碼中,我們可以看到setTimeout函數中除了一個宏任務task1,還有一個微任務task2。當task1被取出來執行時,task2也會被執行。代碼的執行順序是:task3->task1->task2。
3. 穩定性不同
由於微任務在當前宏任務執行結束前執行,所以它的執行過程中可能會影響到後續宏任務的執行順序和結果。而宏任務則不存在這種穩定性問題。
//偽代碼
setTimeout(() => {
console.log('task1');
}, 0);
Promise.resolve().then(() => {
console.log('task2');
setTimeout(() => {
console.log('task3');
}, 0);
});
console.log('task4');
在上面的代碼中,task1和task3是兩個宏任務,task2是一個微任務。當JavaScript引擎執行到微任務task2時,它會加入setTimeout任務隊列中,而此時我們並不能確定task1與task3到底哪一個先被執行,因此最後的執行結果也是不穩定的。
4. 舉例說明
setTimeout(() => {
console.log('task1');
}, 0);
Promise.resolve().then(() => {
console.log('task2');
});
console.log('task3');
在上述代碼中,task1是一個宏任務,task2是一個微任務,task3是另一個宏任務。會先執行task3,然後執行task2,最後是task1。
5. 微任務應用舉例
微任務可以用來在事件循環的不同階段間傳遞數據,並且能夠幫助我們利用異步代碼完成一些類似同步的任務。
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => {
resolve(img);
};
img.onerror = (e) => {
reject(e);
};
img.src = url;
});
}
loadImage('https://picsum.photos/200/300').then((img) => {
console.log('圖片下載完成', img.width, img.height);
}).catch((e) => {
console.log('圖片下載失敗', e);
});
console.log('圖片下載開始');
在上述代碼中,我們首先創建了一個Promise對象,將圖片加載操作放在Promise的構造函數中,並將Promise對象返回。當該Promise執行成功後,會在當前宏任務執行結束前被劃分為一個微任務,最後在當前宏任務執行完成後輸出結果。
三、結尾與總結
通過以上的介紹,我們了解了微任務和宏任務的定義、執行時機、存儲方式、穩定性等差異。在實際開發過程中,我們可以應用這些知識來更好地利用異步編程,提高程序的效率。
原創文章,作者:OJGRB,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/361882.html