JS中的宏任務(wù)和微任務(wù)的區(qū)別和用法

宏任務(wù)(macrotask )和微任務(wù)(microtask )

宏任務(wù)和微任務(wù)都是我們?cè)陂_發(fā)工作中經(jīng)常用到的漠另。

宏任務(wù)(macrotask )和微任務(wù)(microtask )

macrotask 和 microtask 表示異步任務(wù)的兩種分類。

在掛起任務(wù)時(shí),JS 引擎會(huì)將所有任務(wù)按照類別分到這兩個(gè)隊(duì)列中颅筋,首先在 macrotask 的隊(duì)列(這個(gè)隊(duì)列也被叫做 task queue)中取出第一個(gè)任務(wù)擒悬,執(zhí)行完畢后取出 microtask 隊(duì)列中的所有任務(wù)順序執(zhí)行秀鞭;之后再取 macrotask 任務(wù)趋观,周而復(fù)始,直至兩個(gè)隊(duì)列的任務(wù)都取完锋边。

“先查看是否有事件可執(zhí)行”,如果有這優(yōu)先級(jí)限制编曼,那應(yīng)該可以這樣理解:

其實(shí)并不止一個(gè)消息隊(duì)列豆巨,有異步隊(duì)列事件隊(duì)列,而事件隊(duì)列總是優(yōu)先于異步隊(duì)列被空閑下來的JS線程取用

宏任務(wù)一般是:包括整體代碼script掐场,setTimeout往扔,setIntervalI/O熊户、UI render萍膛。
微任務(wù)主要是:PromiseObject.observe嚷堡、MutationObserver蝗罗。

  • 宏任務(wù)和微任務(wù)之間的關(guān)系


    宏任務(wù)和微任務(wù)之間的關(guān)系

區(qū)別體現(xiàn)demo

  • 1.Promise在前,setTimeout在后
new Promise((resolve) => {
    console.log('外層宏事件2');
    resolve()
}).then(() => {
    console.log('微事件1');
}).then(()=>{
    console.log('微事件2')
})
console.log('外層宏事件1');
setTimeout(() => {
    //執(zhí)行后 回調(diào)一個(gè)宏事件
    console.log('內(nèi)層宏事件3')
}, 0)

結(jié)果:

外層宏事件2
外層宏事件1
微事件1
微事件2
內(nèi)層宏事件3
  • 2.setTimeout在前蝌戒,Promise在后
setTimeout(() => {
    //執(zhí)行后 回調(diào)一個(gè)宏事件
    console.log('內(nèi)層宏事件3')
}, 0)
console.log('外層宏事件1');

new Promise((resolve) => {
    console.log('外層宏事件2');
    resolve()
}).then(() => {
    console.log('微事件1');
}).then(()=>{
    console.log('微事件2')
})

結(jié)果:

外層宏事件1
外層宏事件2
微事件1
微事件2
內(nèi)層宏事件3

NodeJS的宏任務(wù)和微任務(wù)跟瀏覽器環(huán)境又有什么區(qū)別

瀏覽器的Event loop是在HTML5中定義的規(guī)范串塑,而node中則由libuv庫(kù)實(shí)現(xiàn)。libuv庫(kù)流程大體分為6個(gè)階段:timers北苟,I/O callbacks桩匪,idle、prepare友鼻,poll傻昙,check,close callbacks彩扔,和瀏覽器的microtask妆档,macrotask那一套有區(qū)別。
兩者執(zhí)行的規(guī)則不同借杰,所以不相同过吻。

//            js event loop (指主線程從“任務(wù)隊(duì)列”中循環(huán)讀取任務(wù))
//
//             event queue 可能同時(shí)不止一個(gè)
//
//            宏任務(wù)(macrotask)event queue (macro-task(宏任務(wù)):script(主程序代碼),,setTimeout,setInterval, I/O, setImmediate(node環(huán)境),UI rendering)
//            ^
//            | 異步
//     主線程->
//          | |  異步
//          | V
//          | 微任務(wù)(microtask) event queue (micro-task(微任務(wù)):Promise纤虽,process.nextTick(node環(huán)境)乳绕,Object.observe, MutationObserver)
//          |
//          V
//          如果是瀏覽器環(huán)境 click等事件隊(duì)列總是優(yōu)先于異步隊(duì)列被空閑下來的JS線程取用

// 執(zhí)行順序   script(主程序代碼)—>process.nextTick—>Promises…——>setTimeout——>setInterval——>setImmediate——> I/O——>UI rendering

// nextTick 優(yōu)先級(jí)比 Promise 等 microTask 高,setTimeout和setInterval優(yōu)先級(jí)比setImmediate高

瀏覽器環(huán)境

瀏覽器環(huán)境下的 異步任務(wù) 分為 宏任務(wù)(macroTask) 和 微任務(wù)(microTask):

宏任務(wù)(macroTask):script 中代碼逼纸、setTimeout洋措、setIntervalI/O杰刽、UI render菠发;

微任務(wù)(microTask): PromiseObject.observe贺嫂、MutationObserver滓鸠。

當(dāng)滿足執(zhí)行條件時(shí),宏任務(wù)(macroTask) 和 微任務(wù)(microTask) 會(huì)各自被放入對(duì)應(yīng)的隊(duì)列:宏隊(duì)列(Macrotask Queue) 和 微隊(duì)列(Microtask Queue) 中等待執(zhí)行第喳。

Node 環(huán)境

在 Node 環(huán)境中 任務(wù)類型 相對(duì)就比瀏覽器環(huán)境下要復(fù)雜一些:

microTask:微任務(wù)糜俗;

nextTick:process.nextTick;

timers:執(zhí)行滿足條件的 setTimeout 曲饱、setInterval 回調(diào)悠抹;

I/O callbacks:是否有已完成的 I/O 操作的回調(diào)函數(shù),來自上一輪的 poll 殘留扩淀;

poll:等待還沒完成的 I/O 事件楔敌,會(huì)因 timers 和超時(shí)時(shí)間等結(jié)束等待;

check:執(zhí)行 setImmediate 的回調(diào)驻谆;

close callbacks:關(guān)閉所有的 closing handles 卵凑,一些 onclose 事件;
idle/prepare 等等:可忽略旺韭。

因此氛谜,也就產(chǎn)生了執(zhí)行事件循環(huán)相應(yīng)的任務(wù)隊(duì)列 Timers Queue、I/O Queue区端、Check Queue 和 Close Queue值漫。
2.執(zhí)行過程
瀏覽器環(huán)境
先執(zhí)行<script>中的同步任務(wù),然后所有微任務(wù)织盼,一個(gè)宏任務(wù)杨何,所有微任務(wù),一個(gè)宏任務(wù)......

執(zhí)行完主執(zhí)行線程中的任務(wù)沥邻;

取出 Microtask Queue 中任務(wù)執(zhí)行直到清空危虱;

取出 Macrotask Queue 中一個(gè)任務(wù)執(zhí)行;

重復(fù) 2 和 3 唐全。

需要 注意 的是:

在瀏覽器頁(yè)面中可以認(rèn)為初始執(zhí)行線程中沒有代碼埃跷,每一個(gè)<script>中的代碼是一個(gè)獨(dú)立的 task 蕊玷,即會(huì)執(zhí)行完前面的<script>中創(chuàng)建的 microTask 再執(zhí)行后面的<script>中的同步代碼;
如果 microTask 一直被添加弥雹,則會(huì)繼續(xù)執(zhí)行 microTask 垃帅,“卡死” macroTask;
部分版本瀏覽器有執(zhí)行順序與上述不符的情況剪勿,可能是不符合標(biāo)準(zhǔn)或 js 與 html 部分標(biāo)準(zhǔn)沖突贸诚;
Promise 的thencatch才是 microTask ,本身的內(nèi)部代碼不是厕吉;
個(gè)別瀏覽器獨(dú)有API未列出酱固。

Node 環(huán)境
循環(huán)之前
在進(jìn)入第一次循環(huán)之前,會(huì)先進(jìn)行如下操作:

同步任務(wù)头朱;
發(fā)出異步請(qǐng)求运悲;
規(guī)劃定時(shí)器生效的時(shí)間;
執(zhí)行process.nextTick()髓窜。

開始循環(huán)
循環(huán)中進(jìn)行的操作:

清空當(dāng)前循環(huán)內(nèi)的 Timers Queue扇苞,清空 NextTick Queue,清空 Microtask Queue寄纵;
清空當(dāng)前循環(huán)內(nèi)的 I/O Queue,清空NextTick Queue脖苏,清空 Microtask Queue程拭;
清空當(dāng)前循環(huán)內(nèi)的 Check Queue,清空 NextTick Queue棍潘,清空 Microtask Queue恃鞋;
清空當(dāng)前循環(huán)內(nèi)的 Close Queue,清空 NextTick Queue亦歉,清空Microtask Queue恤浪;
進(jìn)入下輪循環(huán)。

可以看出肴楷,nextTick 優(yōu)先級(jí)比 PromisemicroTask 高水由,setTimeoutsetInterval優(yōu)先級(jí)比setImmediate高。
注意
在整個(gè)過程中赛蔫,需要 注意 的是:

如果在 timers 階段執(zhí)行時(shí)創(chuàng)建了setImmediate 則會(huì)在此輪循環(huán)的 check 階段執(zhí)行砂客,如果在 timers 階段創(chuàng)建了setTimeout,由于 timers 已取出完畢呵恢,則會(huì)進(jìn)入下輪循環(huán)鞠值,check 階段創(chuàng)建 timers 任務(wù)同理;

setTimeout優(yōu)先級(jí)比setImmediate高渗钉,但是由于setTimeout(fn,0)的真正延遲不可能完全為 0 秒彤恶,可能出現(xiàn)先創(chuàng)建的setTimeout(fn,0)而比setImmediate的回調(diào)后執(zhí)行的情況。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市声离,隨后出現(xiàn)的幾起案子芒炼,更是在濱河造成了極大的恐慌,老刑警劉巖抵恋,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件焕议,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡弧关,警方通過查閱死者的電腦和手機(jī)盅安,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來世囊,“玉大人别瞭,你說我怎么就攤上這事≈旰叮” “怎么了蝙寨?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)嗤瞎。 經(jīng)常有香客問我墙歪,道長(zhǎng),這世上最難降的妖魔是什么贝奇? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任虹菲,我火速辦了婚禮,結(jié)果婚禮上掉瞳,老公的妹妹穿的比我還像新娘毕源。我一直安慰自己,他們只是感情好陕习,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布霎褐。 她就那樣靜靜地躺著,像睡著了一般该镣。 火紅的嫁衣襯著肌膚如雪冻璃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天拌牲,我揣著相機(jī)與錄音俱饿,去河邊找鬼。 笑死塌忽,一個(gè)胖子當(dāng)著我的面吹牛拍埠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播土居,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼枣购,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼嬉探!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起棉圈,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤涩堤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后分瘾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體胎围,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年德召,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了白魂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡上岗,死狀恐怖福荸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情肴掷,我是刑警寧澤敬锐,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站呆瞻,受9級(jí)特大地震影響台夺,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜痴脾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一谒养、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧明郭,春花似錦、人聲如沸丰泊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)瞳购。三九已至话侄,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間学赛,已是汗流浹背年堆。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留盏浇,地道東北人变丧。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像绢掰,于是被迫代替她去往敵國(guó)和親痒蓬。 傳聞我的和親對(duì)象是個(gè)殘疾皇子童擎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容