摘要:接下來處理微任務隊列,打印,后面一個不會有任何打印,但是會執(zhí)行執(zhí)行后面的代碼打印進入第二次事件循環(huán),執(zhí)行宏任務隊列打印
事件循環(huán)機制
理解js的事件循環(huán)機制,能夠很大程度的幫我們更深層次的理解平時遇到的一些很疑惑的問題
簡單版本下面來看一段代碼,想想它的結果和你的結果是否一樣
setTimeout(function() { console.log(1) }, 0) console.log(2) // 執(zhí)行結果是 2 1
我們可以將js的任務分為同步任務和異步任務, 按照這種分類js的執(zhí)行機制如下
任務執(zhí)行隊列分為同步任務隊列和異步任務隊列
代碼執(zhí)行時,遇到同步代碼,會被直接推入同步任務隊列并依次執(zhí)行
遇到異步代碼(如setTimeout、setInterval), 會被直接推入異步任務隊列
當同步任務隊列執(zhí)行完畢,這個時候異步任務隊列的任務會被依次推入同步任務隊列并依次執(zhí)行
所以上面的代碼執(zhí)行的時候, setTimeout()不會被立即執(zhí)行,會被推到異步任務隊列里面, 之后再執(zhí)行console.log(2), 同步任務隊列任務執(zhí)行完畢之后,會去異步任務隊列的任務會被依次推到 同步任務隊列并執(zhí)行
終極版本下面來看一段代碼,想想它的結果和你的結果是否一樣
setTimeout(function() { console.log(1) }, 0) new Promise(function(resolve, reject) { console.log(2) resolve() }).then((res) => { console.log(3) }) console.log(4) // 執(zhí)行結果是 2 4 3 1
js異步任務按照準確的劃分,應該將任務分為
宏任務: setTimeout、setInterval
微任務: 例如Promise.then方法。注意new Promsie()的時候是同步,立即執(zhí)行。
注意: 現(xiàn)在有三個隊列: 同步隊列(也稱執(zhí)行棧)、宏任務隊列、微任務隊列
所以針對這種機制,js的事件循環(huán)機制應該是這樣的
遇到同步代碼,依次推入同步隊列并執(zhí)行
當遇到setTimeout、setInterval,會被推到宏任務隊列
如果遇到.then,會被當作微任務,被推入微任務隊列
同步隊列執(zhí)行完畢,然后會去微隊列取任務,直到微隊列清空。然后檢查宏隊列,去宏隊列取任務,并且每一個宏任務執(zhí)行完畢都會去微隊列跑一遍,看看有沒有新的微任務,有的話再把微任務清空。這樣依次循環(huán)
console.log(1); setTimeout(() => { console.log("setTimeout"); }, 0); let promise = new Promise(resolve => { console.log(3); resolve(); }).then(data => { console.log(100); }).then(data => { console.log(200); }); console.log(2);
所以對于以上的代碼執(zhí)行流程如下:
遇到同步任務先輸出1。
setTimeout是宏任務,會先放到宏任務隊列中。
new Promise是立即執(zhí)行的,所以會先輸出3。
而Promise.then是微任務,會依次排列到微任務隊列中,繼續(xù)向下執(zhí)行輸出2。
現(xiàn)在執(zhí)行棧中的任務已經(jīng)清空,再將微任務隊列清空,依次輸出100和200。
然后每次取出一個宏任務,因為現(xiàn)在只有一個宏任務,所以最后輸出setTimeout。
async/await async當我們在函數(shù)前使用async的時候,使得該函數(shù)返回的是一個Promise對象
async function test() { return 1 // async的函數(shù)會在這里幫我們隱士使用Promise.resolve(1) } // 等價于下面的代碼 function test() { return new Promise(function(resolve, reject) { resolve(1) }) }
可見async只是一個語法糖,只是幫助我們返回一個Promise而已
awaitawait表示等待,是右側「表達式」的結果,這個表達式的計算結果可以是 Promise 對象的值或者一個函數(shù)的值(換句話說,就是沒有特殊限定)。并且只能在帶有async的內(nèi)部使用
使用await時,會從右往左執(zhí)行,當遇到await時,會阻塞函數(shù)內(nèi)部處于它后面的代碼,去執(zhí)行該函數(shù)外部的同步代碼,當外部同步代碼執(zhí)行完畢,再回到該函數(shù)內(nèi)部執(zhí)行剩余的代碼, 并且當await執(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( "setTimeout" ) }, 0 ) async1(); new Promise( function ( resolve ) { console.log( "promise1" ) resolve(); } ).then( function () { console.log( "promise2" ) } ) console.log( "script end" )
下面是在chrome瀏覽器上輸出的結果
使用事件循環(huán)機制分析:
首先執(zhí)行同步代碼,console.log( "script start" )
遇到setTimeout,會被推入宏任務隊列
執(zhí)行async1(), 它也是同步的,只是返回值是Promise,在內(nèi)部首先執(zhí)行console.log( "async1 start" )
然后執(zhí)行async2(), 然后會打印console.log( "async2" )
從右到左會執(zhí)行, 當遇到await的時候,阻塞后面的代碼,去外部執(zhí)行同步代碼
進入 new Promise,打印console.log( "promise1" )
將.then放入事件循環(huán)的微任務隊列
繼續(xù)執(zhí)行,打印console.log( "script end" )
外部同步代碼執(zhí)行完畢,接著回到async1()內(nèi)部, 由于async2()其實是返回一個Promise, await async2()相當于獲取它的值,其實就相當于這段代碼Promise.resolve(undefined).then((undefined) => {}),所以.then會被推入微任務隊列, 所以現(xiàn)在微任務隊列會有兩個任務。接下來處理微任務隊列,打印console.log( "promise2" ),后面一個.then不會有任何打印,但是會執(zhí)行
執(zhí)行后面的代碼, 打印console.log( "async1 end" )
進入第二次事件循環(huán),執(zhí)行宏任務隊列, 打印console.log( "setTimeout" )
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://systransis.cn/yun/100510.html
摘要:由于是單線程的,這些方法就會按順序被排列在一個單獨的地方,這個地方就是所謂執(zhí)行棧。事件隊列每次僅執(zhí)行一個任務,在該任務執(zhí)行完畢之后,再執(zhí)行下一個任務。 Event Loop 是 JavaScript 異步編程的核心思想,也是前端進階必須跨越的一關。同時,它又是面試的必考點,特別是在 Promise 出現(xiàn)之后,各種各樣的面試題層出不窮,花樣百出。這篇文章從現(xiàn)實生活中的例子入手,讓你徹底理解 E...
摘要:下面開始分析開頭的代碼第一輪事件循環(huán)流程整體作為第一個宏任務進入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務中。 先上一道常見的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...
摘要:圖片轉引自的演講和兩個定時器中回調(diào)的執(zhí)行邏輯便是典型的機制。異步編程關于異步編程我的理解是,在執(zhí)行環(huán)境所提供的異步機制之上,在應用編碼層面上實現(xiàn)整體流程控制的異步風格。 問題背景 在一次開發(fā)任務中,需要實現(xiàn)如下一個餅狀圖動畫,基于canvas進行繪圖,但由于對于JS運行環(huán)境中異步機制的不了解,所以遇到了一個棘手的問題,始終無法解決,之后在與同事交流之后才恍然大悟。問題的根節(jié)在于經(jīng)典的J...
摘要:下面開始分析開頭的代碼第一輪事件循環(huán)流程整體作為第一個宏任務進入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務中。 先上一道常見的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...
摘要:何為事件循環(huán)機制的任務分兩種,分別是同步任務和異步任務。如上圖所示主線程在執(zhí)行代碼的時候,遇到異步任務進入并注冊回調(diào)函數(shù),有了運行結果后將它添加到事件隊列中,然后繼續(xù)執(zhí)行下面的代碼,直到同步代碼執(zhí)行完。 我們知道,JavaScript作為瀏覽器的腳本語言,起初是為了與用戶交互和操作DOM,為了避免因為同時操作了同一DOM節(jié)點而引起沖突,被設計成為一種單線程語言。而單線程語言最大的特性就...
閱讀 1024·2021-11-22 13:52
閱讀 935·2019-08-30 15:44
閱讀 579·2019-08-30 15:43
閱讀 2436·2019-08-30 12:52
閱讀 3483·2019-08-29 16:16
閱讀 644·2019-08-29 13:05
閱讀 2950·2019-08-26 18:36
閱讀 2005·2019-08-26 13:46