最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

前言

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

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

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

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

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

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

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

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

瀏覽器的宏任務(wù)、微任務(wù)

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

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

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

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

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

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

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

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

面試題一

題目如下:

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、宏任務(wù)、微任務(wù)里面的事件如下:

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

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

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

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

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

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

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

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

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

// 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í)行,最后結(jié)果如下:

// 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的架構(gòu)圖:

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

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

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

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

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

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

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

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

node的宏任務(wù)、微任務(wù)

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

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

在微任務(wù)隊列中:

  • next tick queue:process.nextTick;
  • other queue:Promise的then回調(diào)、queueMicrotask;

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

在宏任務(wù)隊列:

  • 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

當(dāng)然,main script 依舊是最先執(zhí)行的,只有main script執(zhí)行結(jié)束后,才會按照上述順序來執(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,

最后的結(jié)果是:

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

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

相關(guān)文章

  • js實現(xiàn)選項卡效果

    js實現(xiàn)選項卡效果

    這篇文章主要為大家詳細(xì)介紹了js實現(xiàn)選項卡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • JavaScritp添加url參數(shù)并將參數(shù)加入到url中及更改url參數(shù)的方法

    JavaScritp添加url參數(shù)并將參數(shù)加入到url中及更改url參數(shù)的方法

    這篇文章給大家介紹javascript添加url參數(shù)方法,將參數(shù)加入到url中,涉及到url添加參數(shù)的相關(guān)知識,關(guān)于js添加url參數(shù)感興趣的朋友可以參考下本篇文章
    2015-10-10
  • 微信小程序之事件交互操作實例分析

    微信小程序之事件交互操作實例分析

    這篇文章主要介紹了微信小程序之事件交互操作,結(jié)合實例形式分析了微信小程序事件響應(yīng)、交互及界面布局等相關(guān)操作技巧與注意事項,需要的朋友可以參考下
    2018-12-12
  • JS實現(xiàn)微信搖一搖原理解析

    JS實現(xiàn)微信搖一搖原理解析

    這篇文章主要為大家詳細(xì)介紹了JS微信搖一搖的實現(xiàn)原理,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • JavaScript語法約定和程序調(diào)試原理解析

    JavaScript語法約定和程序調(diào)試原理解析

    這篇文章主要介紹了JavaScript語法約定和程序調(diào)試原理解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-11-11
  • JavaScript era庫的使用詳解

    JavaScript era庫的使用詳解

    這篇本文主要給大家介紹了JavaScript era庫的使用,使用 ora 這個 JavaScript 庫可以在命令行應(yīng)用程序中提供漂亮的加載狀態(tài)提示,本文詳細(xì)介紹如何使用該庫,并結(jié)合多個例子演示其功能,需要的朋友可以參考下
    2024-02-02
  • setInterval計時器不準(zhǔn)的問題解決方法

    setInterval計時器不準(zhǔn)的問題解決方法

    在js中如果打算使用setInterval進行倒數(shù),計時等功能,往往是不準(zhǔn)確的,針對這個問題,本文有個不錯的解決方案
    2014-05-05
  • JavaScript中reduce()的5個基本用法示例

    JavaScript中reduce()的5個基本用法示例

    這篇文章主要給大家介紹了關(guān)于JavaScript中reduce()的5個基本用法示例,文中通過示例代碼以及圖文介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用js具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • 仿google adsense顏色選擇器代碼,從中易廣告聯(lián)盟程序提取

    仿google adsense顏色選擇器代碼,從中易廣告聯(lián)盟程序提取

    仿google adsense顏色選擇器代碼,從中易廣告聯(lián)盟程序提取...
    2007-11-11
  • 深入理解JavaScript系列(27):設(shè)計模式之建造者模式詳解

    深入理解JavaScript系列(27):設(shè)計模式之建造者模式詳解

    這篇文章主要介紹了深入理解JavaScript系列(27):設(shè)計模式之建造者模式詳解,建造者模式可以將一個復(fù)雜對象的構(gòu)建與其表示相分離,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表示,需要的朋友可以參考下
    2015-03-03

最新評論

晋江市| 宜章县| 河曲县| 东乡| 龙南县| 沾益县| 望江县| 江陵县| 巴中市| 六枝特区| 西吉县| 黄龙县| 泰来县| 乾安县| 连城县| 固镇县| 镇赉县| 繁昌县| 清涧县| 荆门市| 龙游县| 仙居县| 涞源县| 信宜市| 繁昌县| 姚安县| 合阳县| 大埔县| 淮安市| 涞源县| 博罗县| 沙河市| 色达县| 庆安县| 建水县| 涟水县| 毕节市| 秦皇岛市| 奇台县| 泗阳县| 南丹县|