您好,登錄后才能下訂單哦!
這篇文章主要講解了“Javascript中Microtask和Macrotask實例分析”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Javascript中Microtask和Macrotask實例分析”吧!
首先我們來看一道題目,如下javascript代碼,執(zhí)行后會在控制臺打印出什么內(nèi)容?
async function async1() { console.log('async1 start'); await async2(); console.log('async1 end'); } async function async2() { console.log('async2 start'); return new Promise((resolve, reject) => { resolve(); console.log('async2 promise'); }) } console.log('script start'); setTimeout(function() { console.log('setTimeout'); }, 0); async1(); new Promise(function(resolve) { console.log('promise1'); resolve(); }).then(function() { console.log('promise2'); }).then(function() { console.log('promise3'); }); console.log('script end')
說實話,真正能在面試中把這道題目答對的前端工程師鳳毛麟角。我們先來瞧一下答案吧。把以上代碼存到test.js文件中,并用node執(zhí)行一下,結(jié)果如下:
如果把以上代碼貼到一個網(wǎng)頁中的script標簽里面,然后打開這個網(wǎng)頁,再打開控制臺,可以看到如下輸出(Chrome 64位 63.0.3239.84):
結(jié)果和node打印的一模一樣。那么為什么是這個順序呢?
我們都知道js的單線程特性(html5的web worker不算在內(nèi)~)以及良好的異步支持。在單線程的前提下,異步任務到底什么時候開始執(zhí)行,其實是有兩個隊列來進行管理,即Macrotask和Microtask(只有一個字母的差距,不要認錯……)。在當前正在執(zhí)行的線程中,如果碰到屬于Macrotask的異步任務,則放入Macrotask隊列;碰到Microtask的異步任務則放入Microtask隊列。注意這里只是把任務放入隊列,并不會執(zhí)行它。等到當前主線程任務執(zhí)行完畢之后,會依次從Microtask隊列中取出任務執(zhí)行,在執(zhí)行期間當然還是遵循碰到異步任務放入相應隊列的原則。等到Microtask任務全部執(zhí)行過了,此時再從Macrotask隊列中取出一個任務執(zhí)行。
屬于Macrotask的任務有:
setTimeout,setInteveral,script標簽,I/O,UI渲染
屬于Microtask的任務有:
Promise,async/await,process.nextTick,Object.observe,MutationObserver
(事實上,即使同樣是Microtask,內(nèi)部也是有優(yōu)先級的差別的,例如NodeJS的實現(xiàn)上,process.nextTick比Promise要先執(zhí)行。相關(guān)問題可以瞧瞧這個連接:https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/ 。反正我瞧到一半就放棄了,好在async/await和Promise沒有優(yōu)先級差別)
然后我們來分析一下本題中的執(zhí)行順序:
【1】第15行執(zhí)行,打印出script start
【2】第16至18行,把回調(diào)任務放入Macrotask (目前Macrotask:第16行setTimeout,Microtask:空)
【3】第20行,執(zhí)行async1函數(shù),先打印出第2行的async1 start
【4】第3行的async2先執(zhí)行,打印出第8行的async2 start
【5】第9行至第12行遇到Promise,先打印出第11行的async2 promise(注意不管你resolve寫在new Promise的函數(shù)什么位置,都跟寫到最后一句一樣?。?/p>
【6】第3行的async2返回了Promise,并且async2前面有await修飾,因此后面第4行的任務被放到Microtask(目前Macrotask:第16行setTimeout,Microtask:第4行)
【7】第22至25行,打印出promise1,并把第26行放入Microtask,注意第28行還沒執(zhí)行到,所以這行什么都不做(目前Macrotask:第16行setTimeout,Microtask:第4行,第26行)
【8】第30行打印script end(目前Macrotask:第16行setTimeout,Microtask:第4行,第26行)
【9】腳本主線程執(zhí)行結(jié)束,現(xiàn)在拿出來一個Microtask,即第4行,打印async1 end(目前Macrotask:第16行setTimeout,Microtask:第26行)
【10】再拿出來一個Microtask,即第26行,打印promise2,此時由于第26行后面跟著then,所以把第28行插入Microtask(目前Macrotask:第16行setTimeout,Microtask:第28行)
【11】再拿出來一個Microtask,即第28行,打印promise3(目前Macrotask:第16行的setTimeout,Microtask:空)
【12】Microtask沒有了,執(zhí)行下一個Macrotask,即第16行的setTimeout,打印setTimeout,結(jié)束
需要注意的是,以下兩種寫法,效果是一模一樣的(resolve的位置無所謂):
寫法1: new Promise((resolve, reject) => { console.log('1111'); resolve(); console.log('2222'); }); 寫法2: new Promise((resolve, reject) => { console.log('1111'); console.log('2222'); resolve(); });
另外,對于Promise的鏈式調(diào)用,如new Promise(....).then(...).then(...)....,一次只放第一個then的內(nèi)容進入Microtask,等第一個then執(zhí)行的時候,會把第二個then放入Microtask,而不是一次把兩個then都放進去。
感謝各位的閱讀,以上就是“Javascript中Microtask和Macrotask實例分析”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Javascript中Microtask和Macrotask實例分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!
免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。