詳解js的宏任務與微任務(event loop)

1. 首先沟饥,國內(nèi)外專家理解

宏任務:script(主程序代碼) setTimeOut setInterVal setImmediate? I/O操作? UI渲染? ? ?requestAnimationFrame

微任務:promise(原生) MutationObserver process.nextTick() mutation Object.observe

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

補充 I/O: (懂得人直接跳過) mouse clicks 蛤袒、keypresses宙搬、network events

js 內(nèi)部執(zhí)行機制:如下圖

最經(jīng)典的圖如下:

先思考一個問題?setTimeout(fn,0) 這樣的代碼舶沛,0秒后立即執(zhí)行???浸策,你太天真了娘摔!

setTimeout(fn,0)的含義是,指定某個任務在主線程最早可得的空閑時間執(zhí)行拴驮,意思就是不用再等多少秒了谍失,只要主線程執(zhí)行棧內(nèi)的同步任務全部執(zhí)行完成,棧為空就馬上執(zhí)行莹汤。

事件循環(huán)快鱼、宏任務、微任務關系如下:


2. 接著纲岭,總結(jié)抹竹。

有如下代碼:

console.log('1');// 主程序首先執(zhí)行

? ? setTimeout(function () { // 將事件插入了"任務隊列",必須等到當前代碼(執(zhí)行棧)執(zhí)行完止潮,主線程才會去執(zhí)行它指定的回調(diào)函數(shù)

? ? ? ? console.log('2');

? ? ? ? process.nextTick(function () {

? ? ? ? ? ? console.log('3');

? ? ? ? })

? ? ? ? new Promise(function (resolve) {

? ? ? ? ? ? console.log('4');

? ? ? ? ? ? resolve();

? ? ? ? }).then(function () {

? ? ? ? ? ? console.log('5')

? ? ? ? })

? ? })

? ? new Promise(function (resolve) {

? ? ? ? console.log('6');

? ? ? ? resolve();

? ? }).then(function () {

? ? ? ? console.log('7')

? ? })

? ? process.nextTick(function () {

? ? ? ? console.log('8'); // 在當前"執(zhí)行棧"的尾部-->下一次Event Loop(主線程讀取"任務隊列")之前-->觸發(fā)process指定的回調(diào)函數(shù)

? ? })

? ? setImmediate(() => {

? ? ? ? console.info('9')? // 主線程和事件隊伍的函數(shù)執(zhí)行完成之后立即執(zhí)行? 和setTimeOut(fn,0)差不多

? ? })

? ? new Promise(function (resolve) {

? ? ? ? console.log('10');

? ? ? ? resolve();

? ? }).then(function () {

? ? ? ? console.log('11')

? ? })

? ? setTimeout(function () {

? ? ? ? console.log('12');

? ? ? ? setImmediate(() => {

? ? ? ? ? ? console.info('13')

? ? ? ? })

? ? ? ? process.nextTick(function () {

? ? ? ? ? ? console.log('14');

? ? ? ? })

? ? ? ? new Promise(function (resolve) {

? ? ? ? ? ? console.log('15');

? ? ? ? ? ? resolve();

? ? ? ? }).then(function () {

? ? ? ? ? ? console.log('16')

? ? ? ? })

? ? })

? ? process.nextTick(function () {

? ? ? ? console.log('17');

? ? })


圖片如下:

輸出的結(jié)果是:1窃判、6、10喇闸、7袄琳、11询件、9、2唆樊、4宛琅、5、8逗旁、17嘿辟、3、12片效、15红伦、16、13淀衣、14

分析:

a.?setTimeOut昙读、process.nextTick、setImmediate膨桥、promise 的區(qū)別

setTimeOut? ?將事件插入了"任務隊列"箕戳,必須等到當前代碼(執(zhí)行棧)執(zhí)行完,主線程才會去執(zhí)行它指定的回調(diào)函數(shù);

process.nextTick??在當前"執(zhí)行棧"的尾部-->下一次Event Loop(主線程讀取"任務隊列")之前-->觸發(fā)process指定的回調(diào)函數(shù)

setImmediate??主線程和事件隊伍的函數(shù)執(zhí)行完成之后立即執(zhí)行 和setTimeOut(fn,0)差不多

b.?

第一步. script整體代碼被執(zhí)行国撵,執(zhí)行過程為

a. 首先陵吸,執(zhí)行script, console.log(1)

b. 創(chuàng)建setTimeout macro-task,? 由于是setTimeOut(fn,0),所有放在當前“執(zhí)行棧”的尾部介牙,默認是0.4毫秒

c. 創(chuàng)建micro-task Promise.then 的回調(diào)壮虫,并執(zhí)console.log(6),?

d. process.nextTick 創(chuàng)建micro-task,在當前"執(zhí)行棧"的尾部-->下一次Event Loop(主線程讀取"任務隊列")之前-->觸發(fā)process指定的回調(diào)函數(shù)

e. 創(chuàng)建setImmediate macro-task,主線程和事件隊伍的函數(shù)執(zhí)行完成后立即執(zhí)行

f. 創(chuàng)建micro-task Promise.then 的回調(diào),并執(zhí)console.log(10),?

g. 創(chuàng)建setTimeout macro-task,? 由于是setTimeOut(fn,0),所有放在當前“執(zhí)行椈反。”的尾部囚似,默認是0.4毫秒

h. process.nextTick 創(chuàng)建micro-task,在當前"執(zhí)行棧"的尾部-->下一次Event Loop(主線程讀取"任務隊列")之前-->觸發(fā)process指定的回調(diào)函數(shù)

第一個過程過后,已經(jīng)輸出了1 6 10 , 查看micro-task 并執(zhí)行回調(diào)线得,輸出 7饶唤,11,同步執(zhí)行?setImmediate 輸出9 ->1 6 10 7 11 9

此時第一個執(zhí)行過程執(zhí)行完贯钩,執(zhí)行setTimeOut(fn,0)募狂,輸出:2 4 5 ,里面包含了一個process.nextTick角雷,放在當前“執(zhí)行椈銮睿”的尾部,執(zhí)行 之前的process.nextTick(d勺三、h),? 輸出:8 17 雷滚,再輸出:3

再下一個事件循環(huán),輸出 12 15 16 13 14

總體輸出為:? ?1 6 10 7 11 9?2 4 5 8 17 3?12 15 16 13 14

思考:

如果把第一個setTimeout(b)改成setTimeOut(fn,1000)吗坚,如下:


輸出結(jié)果為:1 6 10 7 11 9 8 17 12 15 16 13 14 2 4 5 3?


這里可以思考祈远,為什么process.nextTick(8 17)在? g. 創(chuàng)建setTimeout macro-task,之前呆万?

再考慮如下:


輸出如下:


在process.nextTick 前面加了一個事件:setTimeout(function () {? ?console.log('18');? ? })车份,輸出是 18 在 8 之前谋减,

得出結(jié)論:

js 主程序 執(zhí)行完-> 微任務(全部執(zhí)行)->setImmediate->(setTimeOut(fu,0)與process.nextTick,那個在前面就先執(zhí)行誰躬充,完成一個事件循環(huán))->再到下一個事件循環(huán)


3. 推薦的官方文檔

https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/?utm_source=html5weekly

http://lynnelv.github.io/js-event-loop-nodejs

https://zhuanlan.zhihu.com/p/34182184

https://zhuanlan.zhihu.com/p/33058983

https://link.juejin.im/?target=https%3A%2F%2Fjakearchibald.com%2F2015%2Ftasks-microtasks-queues-and-schedules

https://link.juejin.im/?target=https%3A%2F%2Fhackernoon.com%2Funderstanding-js-the-event-loop-959beae3ac40

https://link.juejin.im/?target=https%3A%2F%2Fwww.oschina.net%2Ftranslate%2Funderstanding-process-next-tick

https://link.juejin.im/?target=https%3A%2F%2Fhtml.spec.whatwg.org%2Fmultipage%2Fwebappapis.html

https://link.juejin.im/?target=https%3A%2F%2Fnodejs.org%2Fen%2Fdocs%2Fguides%2Fevent-loop-timers-and-nexttick

https://link.juejin.im/?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fzh-CN%2Fdocs%2FWeb%2FAPI%2FWindow%2FrequestAnimationFrame

https://link.juejin.im/?target=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FAPI%2FMutationObserver

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市讨便,隨后出現(xiàn)的幾起案子充甚,更是在濱河造成了極大的恐慌,老刑警劉巖霸褒,帶你破解...
    沈念sama閱讀 222,681評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件伴找,死亡現(xiàn)場離奇詭異,居然都是意外死亡废菱,警方通過查閱死者的電腦和手機技矮,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殊轴,“玉大人衰倦,你說我怎么就攤上這事∨岳恚” “怎么了樊零?”我有些...
    開封第一講書人閱讀 169,421評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長孽文。 經(jīng)常有香客問我驻襟,道長,這世上最難降的妖魔是什么芋哭? 我笑而不...
    開封第一講書人閱讀 60,114評論 1 300
  • 正文 為了忘掉前任沉衣,我火速辦了婚禮,結(jié)果婚禮上减牺,老公的妹妹穿的比我還像新娘豌习。我一直安慰自己,他們只是感情好拔疚,可當我...
    茶點故事閱讀 69,116評論 6 398
  • 文/花漫 我一把揭開白布斑鸦。 她就那樣靜靜地躺著,像睡著了一般草雕。 火紅的嫁衣襯著肌膚如雪巷屿。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,713評論 1 312
  • 那天墩虹,我揣著相機與錄音嘱巾,去河邊找鬼憨琳。 笑死,一個胖子當著我的面吹牛旬昭,可吹牛的內(nèi)容都是我干的篙螟。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼问拘,長吁一口氣:“原來是場噩夢啊……” “哼遍略!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起骤坐,我...
    開封第一講書人閱讀 40,116評論 0 277
  • 序言:老撾萬榮一對情侶失蹤绪杏,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后纽绍,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蕾久,經(jīng)...
    沈念sama閱讀 46,651評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,714評論 3 342
  • 正文 我和宋清朗相戀三年拌夏,在試婚紗的時候發(fā)現(xiàn)自己被綠了僧著。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,865評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡障簿,死狀恐怖盹愚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情站故,我是刑警寧澤杯拐,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站世蔗,受9級特大地震影響端逼,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜污淋,卻給世界環(huán)境...
    茶點故事閱讀 42,211評論 3 336
  • 文/蒙蒙 一顶滩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧寸爆,春花似錦礁鲁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至魔种,卻和暖如春析二,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評論 1 274
  • 我被黑心中介騙來泰國打工叶摄, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留属韧,地道東北人。 一個月前我還...
    沈念sama閱讀 49,299評論 3 379
  • 正文 我出身青樓蛤吓,卻偏偏與公主長得像宵喂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子会傲,可洞房花燭夜當晚...
    茶點故事閱讀 45,870評論 2 361

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