10分鍾了解js的宏任務和微任務


熟悉宏任務和微任務以及js(nodejs)事件循環機制,在寫業務代碼還是自己寫庫,或者看源碼都是那么重要

看了部分文檔,自己總結和實踐了一下

js中同步任務、宏任務和微任務介紹

同步任務: 普通任務

宏任務(異步任務,包括各種DOM事件) 來自於h5規范

分類: I/O(網絡,文件,數據庫I/O) setTimeout setInterval requestAnimationFrame(下次頁面重繪前所執行的操作, 瀏覽器環境才有) setImmediate(nodejs才有)

  1. 宏任務所處的隊列:宏任務隊列
  2. 第一個宏任務隊列只執行一個任務,執行主線程js代碼,
  3. 宏任務隊列可以有多個任務

微任務(異步任務) 來自於h5規范

分類: new Promise().then(回調)、 process.nextTick()(nodejs才有)

  1. 微任務所處的隊列:微任務隊列
  2. 只有一個微任務隊列
  3. 在上一個宏任務隊列執行完畢后,如果有微任務隊列就會執行微任務隊列中的所有任務;

執行順序

當主線程js代碼(屬於宏任務第一隊列)執行完畢后,如果有微任務,則優先執行微任務(process.nextTick優先執行),然后才執行宏任務

nodejs事件輪詢(循環)機制(宏任務)介紹(借助libuv(c / c++)庫實現)

執行順序:

  1. timer: 定時器階段 計時和執行到點的回調函數 settimeout
  2. pending callbacks 處理某些系統操作(TCP連接錯誤等)
  3. idle prepare 准備工作(nodejs才有)
  4. poll 輪詢階段(輪詢隊列,可以理解為普通異步任務,如網絡請求) 先進先出、依次同步取出輪詢隊列中第一個回調函數執行/知道隊列為空 或者 達到系統最大限制
    如果隊列為空,並且設置過setImmediate,直接進入下一個check階段(未設置:停留在當前poll階段等待,直到隊列添加了回調函數)
  5. check階段,查階段,執行setImmediate(nodejs才有)
  6. close callbacks 關閉階段,執行close事件

舉個栗子

console.log('start') // 順序1 主線程同步任務
setTimeout(() => { // 順序6 宏任務,按照事件輪詢機制執行
  console.log('setTimeout')
}, 0);

new Promise((resolve, reject) => { // new promise 屬於同步主線程任務,優先執行 順序2
  for (let i = 0; i < 5; i++){ // 同步執行主線程任務
    console.log(i)
  }
  setTimeout(() => {
    console.log('promise settimeout') // 順序7 次於上一個異步任務
  }, 0);
  resolve()
}).then(() => {
  console.log('Promise回調執行完畢') // 順序5 new Promise().then(回調)屬於微任務 優於宏任務執行
})

setImmediate(function (params) { // 順序8 宏任務執行,按照事件輪詢機制執行
  console.log('setImmediate')
})

process.nextTick(function (params) { // 特例:在同步任務結束后,微任務如果有process.nextTick,優先執行 順序4
  console.log('nextTick')
})

console.log('main process end') // 順序3 主線程同步任務

// start
// 0
// 1
// 2
// 3
// 4
// main process end
// nextTick
// Promise回調執行完畢
// setTimeout
// setImmediate

/**
setImmediate 和 setTimeout 的優先級
一般根據定時器setTimeout waittime決定
 */

var t1 = +new Date();
setImmediate(function () {
    console.log('1');
});
setTimeout(function () {
    console.log('2');
},20);

console.log('3');
var t2 = +new Date();
console.log('time: ' + (t2 - t1));
//輸出
// 3
// time: 23
// 2
// 1

var t1 = +new Date();
setImmediate(function () {
    console.log('1');
});
setTimeout(function () {
    console.log('2');
},30);

console.log('3');
var t2 = +new Date();
console.log('time: ' + (t2 - t1));
//輸出
// 3
// time: 23
// 1
// 2


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM