亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

JS事件循環(huán)-微任務-宏任務(原理講解+面試題分析)

 更新時間:2023年01月08日 15:00:48   作者:既白biu  
這篇文章主要介紹了JS事件循環(huán)-微任務-宏任務的原理,本文章含有面試題分析,不管是面試者還是想要學習相關內容的都可以很好的理解、掌握這部分內容,需要的朋友可以參考下

前言

JS代碼在運行時,有兩種運行環(huán)境。

一是在瀏覽器中,二是在node中。

由于JS線程是單線程,在運行JS代碼時,可能會遇到比較耗時的操作,比如setTimeout,或者是發(fā)送網(wǎng)絡請求等,又由于JS線程是單線程,如果在解析耗時的代碼時候,停在了這里,那執(zhí)行代碼的性能將是比較低的。

為了解決此問題,在瀏覽器、node環(huán)境下,其實是有事件循環(huán)機制的。

瀏覽器的事件循環(huán)

瀏覽器的事件循環(huán)

JS線程執(zhí)行代碼時候,遇到比較耗時的操作時,將這些操作交給瀏覽器去處理,然后這些操作會根據(jù)不同的種類放進微任務隊列或者宏任務隊列,宏任務隊列和微任務隊列都不為空的時候,只有等微任務隊列為空,即微任務隊列里面的事件全部都執(zhí)行完之后,才會再去讓宏任務隊列中的事件出棧,之后交由JS線程去處理,執(zhí)行代碼。

事件循環(huán)大概就是如圖所示的流程:

瀏覽器的宏任務、微任務

其實,在瀏覽器拿到那些有些不能同步處理的事件的時候,有的會加入宏任務隊列,有的會加入微任務隊列,那么一般我們如何區(qū)分呢?

一般情況下:加入宏任務隊列和微任務隊列的事件如下:

宏任務隊列(macrotask queue):ajax、setTimeout、setInterval、DOM監(jiān)聽、UI Rendering等

微任務隊列(microtask queue):Promise的then回調、 Mutation Observer API、queueMicrotask()。

那么這些事件的執(zhí)行順序是怎么樣子的呢?

首先,有一個原則,宏任務隊列里面的事件,要執(zhí)行的話,一定是在確保微任務隊列為空的情況下,即微任務隊列里面的事件全部執(zhí)行完的情況。

其次,main script里面的內容是最先執(zhí)行的。

由此,可以得到執(zhí)行順序為:main script > 微任務隊列里面的事件 > 宏任務里面的事件。

面試題一

題目如下:

setTimeout(function () {
  console.log("setTimeout1");
  new Promise(function (resolve) {
    resolve();
  }).then(function () {
    new Promise(function (resolve) {
      resolve();
    }).then(function () {
      console.log("then4");
    });
    console.log("then2");
  });
});

new Promise(function (resolve) {
  console.log("promise1");
  resolve();
}).then(function () {
  console.log("then1");
});

setTimeout(function () {
  console.log("setTimeout2");
});

console.log(2);

queueMicrotask(() => {
  console.log("queueMicrotask1")
});

new Promise(function (resolve) {
  resolve();
}).then(function () {
  console.log("then3");
});

// promise1
// 2
// then1
// queueMicrotask1
// then3
// setTimeout1
// then2
// then4
// setTimeout2

分析如下:

在第一個事件循環(huán)里面,main script、宏任務、微任務里面的事件如下:

在判斷加入宏任務隊列還是微任務隊列時候,遵循如下原則:

宏任務隊列(macrotask queue):ajax、setTimeout、setInterval、DOM監(jiān)聽、UI Rendering等
微任務隊列(microtask queue):Promise的then回調、 Mutation Observer
API、queueMicrotask()。

按照這個原則,第一輪事件循環(huán)里面的事件如下:

先執(zhí)行main script、然后微任務隊列里面的,最后是宏任務隊列里面的

// promise1
// 2
// then1
// queueMicrotask1
// then3

之后執(zhí)行setTimeout1的宏任務,此時第二輪事件循環(huán)里面的內容如下:

第二輪事件循環(huán)執(zhí)行內容如下:

// setTimeout1
// then2
// then4
// setTimeout2

綜上:最后執(zhí)行結果為:

// promise1
// 2
// then1
// queueMicrotask1
// then3
// setTimeout1
// then2
// then4
// setTimeout2

面試題二

題目如下:

// async function bar() {
//   console.log("22222")
//   return new Promise((resolve) => {
//     resolve()
//   })
// }

// async function foo() {
//   console.log("111111")

//   await bar()

//   console.log("33333")
// }

// foo()
// console.log("444444")


async function async1 () {
  console.log('async1 start')
  await async2();
  console.log('async1 end')
}

async function async2 () {
  console.log('async2')
}

console.log('script start')

setTimeout(function () {
  console.log('setTimeout')
}, 0)
 
async1();
 
new Promise (function (resolve) {
  console.log('promise1')
  resolve();
}).then (function () {
  console.log('promise2')
})

console.log('script end')

// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout

第一輪事件循環(huán)里面的事件如下:

然后按照順序執(zhí)行,最后結果如下:

// script start
// async1 start
// async2
// promise1
// script end
// async1 end
// promise2
// setTimeout

node的事件循環(huán)

node的事件循環(huán)

瀏覽器的事件循環(huán)是是根據(jù)HTML5定義的規(guī)范來實現(xiàn)的,不同的瀏覽器可能會有不同的實現(xiàn),而Node中是由libuv實現(xiàn)的。

首先我們看一下node的架構圖:

我們可以從圖中大致看出,事件循環(huán)是在libuv中實現(xiàn)的,libuv主要維護的是一個事件循環(huán)(Event Loop)和 線程池(worker threads)。

libuv是一個多平臺的專注于異步IO的庫,它最初是為Node開發(fā)的,但是現(xiàn)在也被使用到Luvit、Julia、pyuv等其他地方;

EventLoop負責調用系統(tǒng)的一些其他操作:文件的IO、Network、child-processes等

由圖可以看出,事件循環(huán)就像是一個橋梁,是連接著應用程序的JavaScript(左邊部分)和系統(tǒng)調用(右邊線程池部分)之間的通道:

無論是我們的文件IO、數(shù)據(jù)庫、網(wǎng)絡IO、定時器、子進程,在完成對應的操作后,都會將對應的結果和回調函數(shù)放到事件循環(huán)(任務隊列)中;

事件循環(huán)會不斷的從任務隊列中取出對應的事件(回調函數(shù))來執(zhí)行;

但是一次完整的事件循環(huán)Tick分成很多個階段:

  1. 定時器(Timers):本階段執(zhí)行已經(jīng)被 setTimeout() 和 setInterval() 的調度回調函數(shù)。
  2. 待定回調(Pending Callback):對某些系統(tǒng)操作(如TCP錯誤類型)執(zhí)行回調,比如TCP連接時接收到ECONNREFUSED。idle, prepare:僅系統(tǒng)內部使用。
  3. 輪詢(Poll):檢索新的 I/O 事件;執(zhí)行與 I/O 相關的回調;
  4. 檢測(check):setImmediate() 回調函數(shù)在這里執(zhí)行。
  5. 關閉的回調函數(shù):一些關閉的回調函數(shù),如:socket.on(‘close’, …)

node的宏任務、微任務

node中也有微任務和宏任務,執(zhí)行的原則和在瀏覽器中一樣,是先執(zhí)行微任務,然后再執(zhí)行宏任務,但是對于宏任務來說,是按照上圖從上到下的順序執(zhí)行的。

具體對應的常見事件的執(zhí)行順序如下;

在微任務隊列中:

  • next tick queue:process.nextTick;
  • other queue:Promise的then回調、queueMicrotask;

(是按照從上往下的事件順序執(zhí)行)

在宏任務隊列:

  • timer queue:setTimeout、setInterval;
  • poll queue:IO事件;
  • check queue:setImmediate;
  • close queue:close事件

(同樣是按照從上往下的事件順序執(zhí)行)

所以,綜上所述,在每一次事件循環(huán)的tick中,會按照如下順序來執(zhí)行代碼:

next tick microtask queue;
other microtask queue;
timer queue;
poll queue;
check queue;
close queue

當然,main script 依舊是最先執(zhí)行的,只有main script執(zhí)行結束后,才會按照上述順序來執(zhí)行代碼。

面試題一

async function async1() {
  console.log('async1 start')
  await async2()
  console.log('async1 end')
}

async function async2() {
  console.log('async2')
}

console.log('script start')

setTimeout(function () {
  console.log('setTimeout0')
}, 0)

setTimeout(function () {
  console.log('setTimeout2')
}, 300)

setImmediate(() => console.log('setImmediate'));

process.nextTick(() => console.log('nextTick1'));

async1();

process.nextTick(() => console.log('nextTick2'));

new Promise(function (resolve) {
  console.log('promise1')
  resolve();
  console.log('promise2')
}).then(function () {
  console.log('promise3')
})

console.log('script end')

// script start
// async1 start
// async2
// promise1
// promise2
// script end
// nexttick1
// nexttick2
// async1 end
// promise3
// settimetout0
// setImmediate
// setTimeout2

第一輪事件循環(huán)里面的事件如下:

按照順序自左向右執(zhí)行,3s后執(zhí)行setTimeout2,

最后的結果是:

// script start
// async1 start
// async2
// promise1
// promise2
// script end
// nexttick1
// nexttick2
// async1 end
// promise3
// settimetout0
// setImmediate
// setTimeout2

到此這篇關于JS事件循環(huán)-微任務-宏任務(原理講解+面試題分析)的文章就介紹到這了,更多相關循環(huán)-微任務-宏任務內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論