深入了解微任務和宏任務

一、任務隊列的概念

任務隊列是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

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
OJGRB的頭像OJGRB
上一篇 2025-02-25 18:17
下一篇 2025-02-25 18:17

相關推薦

  • Java任務下發回滾系統的設計與實現

    本文將介紹一個Java任務下發回滾系統的設計與實現。該系統可以用於執行複雜的任務,包括可回滾的任務,及時恢復任務失敗前的狀態。系統使用Java語言進行開發,可以支持多種類型的任務。…

    編程 2025-04-29
  • Saturn 定時任務用法介紹

    本文將從以下幾個方面對Saturn定時任務進行詳細的闡述: 一、Saturn 定時任務簡介 Saturn是一個分佈式任務調度系統,支持在線添加、修改定時任務,支持多種任務類型,如J…

    編程 2025-04-29
  • 如何在dolphinscheduler中運行chunjun任務實例

    本文將從多個方面對dolphinscheduler運行chunjun任務實例進行詳細的闡述,包括準備工作、chunjun任務配置、運行結果等方面。 一、準備工作 在運行chunju…

    編程 2025-04-28
  • dotask——高效易用的任務執行框架

    一、任務執行框架介紹 在一個複雜的系統中,通常存在大量的任務需要執行。這些任務包括但不限於:發送郵件、處理數據、調用服務、生成報表等。在傳統的編程模式中,我們往往需要手動編寫任務調…

    編程 2025-04-25
  • 深入解析Vue3 defineExpose

    Vue 3在開發過程中引入了新的API `defineExpose`。在以前的版本中,我們經常使用 `$attrs` 和` $listeners` 實現父組件與子組件之間的通信,但…

    編程 2025-04-25
  • 深入理解byte轉int

    一、位元組與比特 在討論byte轉int之前,我們需要了解位元組和比特的概念。位元組是計算機存儲單位的一種,通常表示8個比特(bit),即1位元組=8比特。比特是計算機中最小的數據單位,是…

    編程 2025-04-25
  • 深入理解Flutter StreamBuilder

    一、什麼是Flutter StreamBuilder? Flutter StreamBuilder是Flutter框架中的一個內置小部件,它可以監測數據流(Stream)中數據的變…

    編程 2025-04-25
  • 深入探討OpenCV版本

    OpenCV是一個用於計算機視覺應用程序的開源庫。它是由英特爾公司創建的,現已由Willow Garage管理。OpenCV旨在提供一個易於使用的計算機視覺和機器學習基礎架構,以實…

    編程 2025-04-25
  • 深入了解scala-maven-plugin

    一、簡介 Scala-maven-plugin 是一個創造和管理 Scala 項目的maven插件,它可以自動生成基本項目結構、依賴配置、Scala文件等。使用它可以使我們專註於代…

    編程 2025-04-25
  • 深入了解LaTeX的腳註(latexfootnote)

    一、基本介紹 LaTeX作為一種排版軟件,具有各種各樣的功能,其中腳註(footnote)是一個十分重要的功能之一。在LaTeX中,腳註是用命令latexfootnote來實現的。…

    編程 2025-04-25

發表回復

登錄後才能評論