1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        JavaScript的事件循環(huán)\運(yùn)行機(jī)制\eventloop

        共 18835字,需瀏覽 38分鐘

         ·

        2021-07-31 03:22

        JavaScript的運(yùn)行機(jī)制是工作中最常碰到的,同時(shí)也是筆試 or 面試中會(huì)被問(wèn)到的問(wèn)題,故在本文整理了JavaScript的運(yùn)行機(jī)制,以供參考。


        JavaScript執(zhí)行機(jī)制,重點(diǎn)有兩點(diǎn):

        1.JavaScript是一門單線程語(yǔ)言。

        2.Event Loop(事件循環(huán))是JavaScript的執(zhí)行機(jī)制。


        既然說(shuō)js是單線程,那就是在執(zhí)行代碼的時(shí)候是從上往下執(zhí)行的,先來(lái)看一段代碼:


         1setTimeout(function(){
        2  console.log('定時(shí)器開始')
        3});
        4
        5new Promise(function(resolve){
        6   console.log('Promise開始');
        7   resolve();
        8}).then(function(){
        9  console.log('執(zhí)行then函數(shù)')
        10});
        11
        12console.log('代碼執(zhí)行結(jié)束');


        輸出結(jié)果:

        Promise開始

        代碼執(zhí)行結(jié)束

        執(zhí)行then函數(shù)

        定時(shí)器開始


        關(guān)于javascript

        javascript是一門單線程語(yǔ)言,在最新的HTML5中提出了Web-Worker, 但javascript是單線程這一核心扔未改變。所以一切javascript版的“多線程”都是用單線程模擬出來(lái)的,一切javascript多線程都是紙老虎


        JS為什么是單線程的

        最初設(shè)計(jì)JS是用來(lái)在瀏覽器驗(yàn)證表單操控DOM元素的是一門腳本語(yǔ)言,如果js是多線程的,那么兩個(gè)線程同時(shí)對(duì)一個(gè)DOM元素進(jìn)行了相互沖突的操作,那么瀏覽器的解析器是無(wú)法執(zhí)行的。


        js為什么需要異步

        如果js中不存在異步,只能自上而下執(zhí)行,如果上一行解析時(shí)間很長(zhǎng),那么下面的代碼就會(huì)被阻塞。對(duì)于用戶而言,阻塞就意味著“卡死”,這樣就導(dǎo)致了很差的用戶體驗(yàn)。比如在進(jìn)行ajax請(qǐng)求的時(shí)候如果沒有返回?cái)?shù)據(jù)后面的代碼就沒辦法執(zhí)行


        js單線程又是如何實(shí)現(xiàn)異步的呢

        js中的異步以及多線程都可以理解成為一種“假象”,就拿h5的WebWorker來(lái)說(shuō),子線程有諸多限制,不能控制DOM,不能修改全局對(duì)象等等,通常只用來(lái)做計(jì)算做數(shù)據(jù)處理。
        這些限制并沒有違背我們之前的觀點(diǎn),所以說(shuō)是“假象”。JS異步的執(zhí)行機(jī)制其實(shí)就是事件循環(huán)(eventloop),理解了eventloop機(jī)制,就理解了js異步的執(zhí)行機(jī)制。


        JS的事件循環(huán)(eventloop)是怎么運(yùn)作的

        事件循環(huán)、eventloop\運(yùn)行機(jī)制 這三個(gè)術(shù)語(yǔ)其實(shí)說(shuō)的是同一個(gè)東西
        “先執(zhí)行同步操作異步操作排在事件隊(duì)列里”這樣的理解其實(shí)也沒有任何問(wèn)題但如果深入的話會(huì)引出很多其他概念,比如event table和event queue, 我們來(lái)看運(yùn)行過(guò)程:

        1. 首先判斷JS是同步還是異步,同步就進(jìn)入主線程運(yùn)行,異步就進(jìn)入event table.

        2. 異步任務(wù)在event table中注冊(cè)事件,當(dāng)滿足觸發(fā)條件后,(觸發(fā)條件可能是延時(shí)也可能是ajax回調(diào)),被推入event queue

        1. 同步任務(wù)進(jìn)入主線程后一直執(zhí)行,直到主線程空閑時(shí),才會(huì)去event queue中查看是否有可執(zhí)行的異步任務(wù),如果有就推入主線程中。

        cf51e2ced8cacc86c53640b930263fe4.webp

        那怎么知道主線程執(zhí)行棧為空啊?js引擎存在monitoring process進(jìn)程,會(huì)持續(xù)不斷的檢查 主線程 執(zhí)行棧是否為空,一旦為空,就會(huì)去event queue那里檢查是否有等待被調(diào)用的函數(shù)。


        1let data = [];
        2$.ajax({
        3    url:www.javascript.com,
        4    data:data,
        5    success:() => {
        6        console.log('發(fā)送成功!');
        7    }
        8})
        9console.log('代碼執(zhí)行結(jié)束');
        • ajax進(jìn)入event table,注冊(cè)回調(diào)函數(shù)success

        • 執(zhí)行 console.log('代碼執(zhí)行結(jié)束')

        • ajax事件完成,回調(diào)函數(shù)success進(jìn)入event queue

        • 主線程從event queue讀取回調(diào)函數(shù)success并執(zhí)行


        setTimeout

        1setTimeout(() => {
        2  console.log('2秒到了')
        3}, 2000)


        setTimeout是異步操作首先進(jìn)入event table, 注冊(cè)的事件就是它的回調(diào),觸發(fā)條件就是2秒之后,當(dāng)滿足條件回調(diào)被推入event queue,當(dāng)主線程空閑時(shí)會(huì)去event queue里查看是否有可執(zhí)行的任務(wù)。


        1console.log(1// 同步任務(wù)進(jìn)入主線程
        2setTimeout(fun(),0)   // 異步任務(wù),被放入event table, 0秒之后被推入event queue里
        3console.log(3// 同步任務(wù)進(jìn)入主線程


        1、3是同步任務(wù)馬上會(huì)被執(zhí)行,執(zhí)行完成之后主線程空閑去event queue(事件隊(duì)列)里查看是否有任務(wù)在等待執(zhí)行,這就是為什么setTimeout的延遲事件是0毫秒?yún)s在最后執(zhí)行的原因

        但setTimeout延時(shí)的時(shí)間有時(shí)候并不是那么準(zhǔn)確


        1setTimeout(() => {
        2  console.log('2秒到了')
        3}, 2000)
        4wait(9999999999)


        分析運(yùn)行過(guò)程:

        1. console進(jìn)入Event Table并注冊(cè),計(jì)時(shí)開始。

        2. 執(zhí)行sleep函數(shù),sleep方法雖然是同步任務(wù)但sleep方法進(jìn)行了大量的邏輯運(yùn)算,耗時(shí)超過(guò)了2秒

        1. 2秒到了,計(jì)時(shí)事件timeout完成,console進(jìn)入Event queue, 但是sleep還沒執(zhí)行完,主線程還被占用,只能等著。

        2. sleep終于執(zhí)行完了, console終于從event queue進(jìn)入了主線程執(zhí)行,這個(gè)時(shí)候已經(jīng)遠(yuǎn)遠(yuǎn)超過(guò)了2秒

        其實(shí)延遲2秒只是表示2秒后,setTimeout里的函數(shù)被推入event queue , 而event queue(事件隊(duì)列)里的任務(wù),只有在主線程空閑時(shí)才會(huì)執(zhí)行。


        上述流程走完,我們知道setTimeout這個(gè)函數(shù),是經(jīng)過(guò)指定時(shí)間后,把要執(zhí)行的任務(wù)(本例子中為console)加入到event queue中, 又因?yàn)閱尉€程任務(wù)要一個(gè)一個(gè)執(zhí)行,如果前面的任務(wù)需要的時(shí)間太久,那么只能等著,導(dǎo)致真正的延遲時(shí)間遠(yuǎn)遠(yuǎn)大于2秒。我們還經(jīng)常遇到setTimeout(fn,0)這樣的代碼,它的含義是,指定某個(gè)任務(wù)在主線最早的空閑時(shí)間執(zhí)行,意思就是不用再等多少秒了, 只要主線程執(zhí)行棧內(nèi)的同步任務(wù)全部執(zhí)行完成,棧為空就馬上執(zhí)行。但是即便主線程為空,0毫秒實(shí)際上也是達(dá)不到的。根據(jù)HTML的標(biāo)準(zhǔn),最低是4毫秒。


        setIntval

        以setIntval(fn,ms)為例,setIntval是循環(huán)執(zhí)行的,setIntval會(huì)每隔指定的時(shí)間將注冊(cè)的函數(shù)置入event queue,不是每過(guò)ms會(huì)執(zhí)行一次fn,而是每過(guò)ms秒,會(huì)有fn進(jìn)入event queue。需要注意一點(diǎn)的是,一旦setIntval的回調(diào)函數(shù)fn執(zhí)行時(shí)間超過(guò)了延遲事件ms,那么就完成看不出來(lái)有時(shí)間間隔了。


        除了廣義的同步任務(wù)和異步任務(wù),我們對(duì)任務(wù)有更精細(xì)的定義:


        • 宏任務(wù) 包含整個(gè)script代碼塊,setTimeout, setIntval

        • 微任務(wù) Promise , process.nextTick


        在劃分宏任務(wù)、微任務(wù)的時(shí)候并沒有提到async/ await的本質(zhì)就是Promise


        那事件循環(huán)機(jī)制到底是怎么樣的?

        不同類型的任務(wù)會(huì)進(jìn)入對(duì)應(yīng)的event queue, 比如setTime和setIntval會(huì)進(jìn)入相同(宏任務(wù))的event queue, 而Promise和process.nextTick會(huì)進(jìn)入相同(微任務(wù))的event queue.



        Promise與事件循環(huán)

        Promise在初始化時(shí),傳入的函數(shù)是同步執(zhí)行的,然后注冊(cè)then回調(diào)。注冊(cè)完之后,繼續(xù)往下執(zhí)行同步代碼,在這之前,then的回調(diào)不會(huì)執(zhí)行。同步代碼塊執(zhí)行完畢后,才會(huì)在事件循環(huán)中檢測(cè)是否有可用的promise回調(diào),如果有,那么執(zhí)行,如果沒有,繼續(xù)下一個(gè)事件循環(huán)。

        1. 宏任務(wù),微任務(wù)都是隊(duì)列, 一段代碼執(zhí)行時(shí),會(huì)先執(zhí)行宏任務(wù)中的同步代碼。2. 進(jìn)行第一輪事件循環(huán)的時(shí)候會(huì)把全部的js腳本當(dāng)成一個(gè)宏任務(wù)來(lái)運(yùn)行。

        3. 如果執(zhí)行中遇到setTimeout之類的宏任務(wù),那么就把這個(gè)setTimeout內(nèi)部的函數(shù)推入[宏任務(wù)的隊(duì)列]中,下一輪宏任務(wù)執(zhí)行時(shí)調(diào)用。

        4. 如果執(zhí)行中遇到promise.then()之類的微任務(wù),就會(huì)推入到[當(dāng)前宏任務(wù)的微任務(wù)隊(duì)列]中, 在本輪宏任務(wù)的同步代碼都執(zhí)行完成后,依次執(zhí)行所有的微任務(wù)。

        5. 第一輪事件循環(huán)中當(dāng)執(zhí)行完全部的同步腳步以及微任務(wù)隊(duì)列中的事件,這一輪事件循環(huán)就結(jié)束了, 開始第二輪事件循環(huán)。

        6. 第二輪事件循環(huán)同理先執(zhí)行同步腳本,遇到其他宏任務(wù)代碼塊繼續(xù)追加到[宏任務(wù)的隊(duì)列]中,遇到微任務(wù),就會(huì)推入到[當(dāng)前宏任務(wù)的微任務(wù)隊(duì)列]中,在本輪宏任務(wù)的同步代碼執(zhí)行都完成后, 依次執(zhí)行當(dāng)前所有的微任務(wù)。

        7. 開始第三輪循環(huán)往復(fù)..


        下面用代碼來(lái)深入理解上面的機(jī)制:


         1setTimeout(function() {
        2    console.log('4')
        3})
        4
        5new Promise(function(resolve{
        6    console.log('1'// 同步任務(wù)
        7    resolve()
        8}).then(function() {
        9    console.log('3')
        10})
        11console.log('2')



        1. 這段代碼作為宏任務(wù),進(jìn)入主線程。

        2. 先遇到setTimeout,那么將其回調(diào)函數(shù)注冊(cè)后分發(fā)到宏任務(wù)event queue.

        3. 接下來(lái)遇到Promise, new Promise立即執(zhí)行,then函數(shù)分發(fā)到微任務(wù)event queue

        4. 遇到console.log(), 立即執(zhí)行

        5. 整體代碼script作為第一個(gè)宏任務(wù)執(zhí)行結(jié)束, 查看當(dāng)前有沒有可執(zhí)行的微任務(wù),執(zhí)行then的回調(diào)。(第一輪事件循環(huán)結(jié)束了,我們開始第二輪循環(huán))

        6. 從宏任務(wù)的event queue開始,我們發(fā)現(xiàn)了宏任務(wù)event queue中setTimeout對(duì)應(yīng)的回調(diào)函數(shù),立即執(zhí)行。執(zhí)行結(jié)果:1-2-3-4


        7. 整體script作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到console.log(1)輸出1

        8. 遇到setTimeout, 其回調(diào)函數(shù)被分發(fā)到宏任務(wù)event queue中。我們暫且記為setTimeout1
          3.遇到process.nextTick(),其回調(diào)函數(shù)被分發(fā)到微任務(wù)event queue中,我們記為process1
          4.遇到Promise, new Promise直接執(zhí)行,輸出7.then被分發(fā)到微任務(wù)event queue中,我們記為then1

        9. 又遇到setTimeout,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)event queue中,我們記為setTimeout2.

        10. 現(xiàn)在開始執(zhí)行微任務(wù), 我們發(fā)現(xiàn)了process1和then1兩個(gè)微任務(wù),執(zhí)行process1,輸出6,執(zhí)行then1,輸出8, 第一輪事件循環(huán)正式結(jié)束, 這一輪的結(jié)果輸出1,7,6,8.那么第二輪事件循環(huán)從setTimeout1宏任務(wù)開始

        11. 首先輸出2, 接下來(lái)遇到了process.nextTick(),統(tǒng)一被分發(fā)到微任務(wù)event queue,記為process2
          8.new Promise立即執(zhí)行,輸出4,then也被分發(fā)到微任務(wù)event queue中,記為then2

        12. 現(xiàn)在開始執(zhí)行微任務(wù),我們發(fā)現(xiàn)有process2和then2兩個(gè)微任務(wù)可以執(zhí)行輸出3,5. 第二輪事件循環(huán)結(jié)束,第二輪輸出2,4,3,5. 第三輪事件循環(huán)從setTimeout2宏任務(wù)開始
          10。直接輸出9,跟第二輪事件循環(huán)類似,輸出9,11,10,12

        13. 完整輸出是1,7,6,8,2,4,3,5,9,11,10,12(請(qǐng)注意,node環(huán)境下的事件監(jiān)聽依賴libuv與前端環(huán)境不完全相同,輸出順序可能會(huì)有誤差)


         1console.log('1')
        2setTimeout(function() {
        3    console.log('2')
        4    process.nextTick(function() {
        5        console.log('3')
        6    })
        7    new Promise(function(resolve{
        8        console.log('4')
        9        resolve()
        10    }).then(function() {
        11        console.log('5')
        12    })
        13})
        14
        15process.nextTick(function() {
        16    console.log('6')
        17})
        18
        19new Promise(function(resolve{
        20    console.log('7')
        21    resolve()
        22}).then(function() {
        23    console.log('8')
        24})
        25
        26setTimeout(function() {
        27    console.log('9')
        28    process.nextTick(function() {
        29        console.log('10')
        30    })
        31    new Promise(function(resolve{
        32        console.log('11')
        33        resolve()
        34    }).then(function() {
        35        console.log('12')
        36    })
        37})


        如果是setTimeout里面嵌套setTimeout, 那么嵌套的setTimeout的宏任務(wù)要在外面的宏任務(wù)排序的后面,往后排??磦€(gè)例子


         1new Promise(function (resolve
        2    console.log('1')// 宏任務(wù)一
        3    resolve()
        4}).then(function () {
        5    console.log('3'// 宏任務(wù)一的微任務(wù)
        6})
        7setTimeout(function () // 宏任務(wù)二
        8    console.log('4')
        9    setTimeout(function () // 宏任務(wù)五
        10        console.log('7')
        11        new Promise(function (resolve{
        12            console.log('8')
        13            resolve()
        14        }).then(function () {
        15            console.log('10')
        16            setTimeout(function () {  // 宏任務(wù)七
        17                console.log('12')
        18            })
        19        })
        20        console.log('9')
        21    })
        22})
        23setTimeout(function () // 宏任務(wù)三
        24    console.log('5')
        25})
        26setTimeout(function () {  // 宏任務(wù)四
        27    console.log('6')
        28    setTimeout(function () // 宏任務(wù)六
        29        console.log('11')
        30    })
        31})
        32console.log('2'// 宏任務(wù)一


        初步總結(jié):宏任務(wù)是一個(gè)棧按先入先執(zhí)行的原則,微任務(wù)也是一個(gè)棧也是先入先執(zhí)行。但是每個(gè)宏任務(wù)都對(duì)應(yīng)會(huì)有一個(gè)微任務(wù)棧,宏任務(wù)在執(zhí)行過(guò)程中會(huì)先執(zhí)行同步代碼再執(zhí)行微任務(wù)棧。


        async/await是什么

        我們創(chuàng)建了promise但不能同步等待它執(zhí)行完成。我們只能通過(guò)then傳一個(gè)回調(diào)函數(shù)這樣很容易再次陷入promise的回調(diào)地獄。實(shí)際上, async/await在底層轉(zhuǎn)換成了promise和then回調(diào)函數(shù),也就是說(shuō), 這是promise的語(yǔ)法糖。每次我們使用await, 解釋器都創(chuàng)建一個(gè)promise對(duì)象,然后把剩下的async函數(shù)中的操作放到then回調(diào)函數(shù)中。async/await的實(shí)現(xiàn),離不開promise. 從字面意思來(lái)理解, async是“異步”的簡(jiǎn)寫,而await是async wait的簡(jiǎn)寫可以認(rèn)為是等待異步方法執(zhí)行完成。


        async/await用來(lái)干什么

        用來(lái)優(yōu)化promise的回調(diào)問(wèn)題,被稱為是異步的終極解決方案


        async/await內(nèi)部做了什么

        async函數(shù)會(huì)返回一個(gè)Promise對(duì)象,如果在函數(shù)中return一個(gè)直接量(普通變量),async會(huì)把這個(gè)直接量通過(guò)Promise.resolve()封裝成Promise對(duì)象。如果你返回了promise那就以你返回的promise為準(zhǔn)。await是在等待,等待運(yùn)行的結(jié)果也就是返回值。await后面通常是一個(gè)異步操作(promise),但是這不代表await后面只能跟異步才做,await后面實(shí)際是可以接普通函數(shù)調(diào)用或者直接量。
        async相當(dāng)于 new Promise,await相當(dāng)于then


        await的等待機(jī)制

        如果await后面跟的不是一個(gè)promise,那await后面表達(dá)式的運(yùn)算結(jié)果就是它等到的東西,如果await后面跟的是一個(gè)promise對(duì)象,await它會(huì)'阻塞'后面的diamante,等著promise對(duì)象resolve, 然后得到resolve的值作為await表達(dá)式的運(yùn)算結(jié)果。但是此"阻塞"非彼“阻塞”,這就是await必須用在async函數(shù)中的原因。async函數(shù)調(diào)用不會(huì)造成"阻塞",它內(nèi)部所有的“阻塞”都被封裝在一個(gè)promise對(duì)象中異步執(zhí)行(這里的阻塞理解成異步等待更合理)


        async/await在使用過(guò)程中有什么規(guī)定

        每個(gè)async方法都返回一個(gè)promise, await只能出現(xiàn)在async函數(shù)中


        async/await在什么場(chǎng)景使用

        單一的promise鏈并不能發(fā)現(xiàn)async/await的優(yōu)勢(shì),但是如果需要處理由多個(gè)promise組成的then鏈的時(shí)候,優(yōu)勢(shì)就能體現(xiàn)出來(lái)了(Promise通過(guò)then鏈來(lái)解決多層回調(diào)的問(wèn)題,現(xiàn)在又用async/awai來(lái)進(jìn)一步優(yōu)化它)


        async/await如何使用

        假設(shè)一個(gè)業(yè)務(wù),分多個(gè)步驟完成,每個(gè)步驟都是異步的且依賴于上一個(gè)步驟的結(jié)果


         1function myPromise(n{
        2    return new Promise(resolve => {
        3        console.log(n)
        4        setTimeout(() => resolve(n+1), n)
        5    })
        6}
        7function step1(n{
        8    return myPromise(n)
        9}
        10function step2(n{
        11    return myPromise(n)
        12}
        13function step3(n{
        14    return myPromise(n)
        15}
        16
        17//如果用 Promise 實(shí)現(xiàn)
        18step1(1000)
        19.then(a => step2(a))
        20.then(b => step3(b))
        21.then(result => {
        22    console.log(result)
        23})
        24
        25//如果用 async/await 來(lái)實(shí)現(xiàn)呢
        26async function myResult() {
        27    const a = await step1(1000)
        28    const b = await step2(a)
        29    const result = await step3(b)
        30    return result
        31}
        32myResult().then(result => {
        33    console.log(result)
        34}).catch(err => {
        35    // 如果myResult內(nèi)部有語(yǔ)法錯(cuò)誤會(huì)觸發(fā)catch方法
        36})


        看的出來(lái)async/await的寫法更多優(yōu)雅一些要比promise的鏈接調(diào)用更多直觀也易于維護(hù)

        我們來(lái)看在任務(wù)隊(duì)列中async/await的運(yùn)行機(jī)制,先給出大概方向再通過(guò)案例來(lái)證明:

        1. async定義的是一個(gè)promise函數(shù)和普通函數(shù)一樣只要不調(diào)用就不會(huì)進(jìn)入事件隊(duì)列。

        2. async內(nèi)部如果沒有主動(dòng)return promise, 那么async會(huì)把函數(shù)的返回值用promise包裝

        3. await關(guān)鍵字必須出現(xiàn)在async函數(shù)中,await后面不是必須要跟一個(gè)異步操作,也可以是一個(gè)普通表達(dá)式

        4. 遇到await關(guān)鍵字,await右邊的語(yǔ)句會(huì)被立即執(zhí)行然后await下面的代碼進(jìn)入等待狀態(tài),等待await得到結(jié)果。await后面如果不是promise對(duì)象,await會(huì)阻塞后面的代碼,先執(zhí)行async外面的同步代碼,同步代碼執(zhí)行完,再回到async內(nèi)部,把這個(gè)非promise的東西,作為await表達(dá)式的結(jié)果。await后面如果是promise對(duì)象,await也會(huì)暫停async后面的代碼,先執(zhí)行async外面的同步代碼,等著promise對(duì)象fulfilled,然后把resolve的參數(shù)作為await表達(dá)式的運(yùn)算結(jié)果。


         1setTimeout(function () {
        2  console.log('6')
        3}, 0)
        4console.log('1')
        5async function async1() {
        6  console.log('2')
        7  await async2()
        8  console.log('5')
        9}
        10async function async2() {
        11  console.log('3')
        12}
        13async1()
        14console.log('4')
        1. 6是宏任務(wù)在下一輪事件循環(huán)執(zhí)行

        2. 先同步輸出1,然后調(diào)用async1(),輸出2

        1. await async2()會(huì)先運(yùn)行async2(), 5進(jìn)入等待狀態(tài)

        2. 輸出3, 這個(gè)時(shí)候先執(zhí)行async函數(shù)外的同步代碼輸出4.

        1. 最后await拿到等待的結(jié)果繼續(xù)往下執(zhí)行輸出5.
          6, 進(jìn)入第二輪事件循環(huán)輸出6.
          12bf13e70f6b7d06f72f0f6ff1b75f0e.webp


        測(cè)試代碼的輸出結(jié)果,看到async1函數(shù)輸出2, 立馬執(zhí)行await 的async2函數(shù),輸出3, 但是沒有立即返回,而是先執(zhí)行async2外面的同步代碼,最后得到返回

        值111111給await async2函數(shù),


        3c805d5d01a04a56d22fea15f625c049.webp


         1console.log('1')
        2async function async1() {
        3  console.log('2')
        4  await 'await的結(jié)果'
        5  console.log('5')
        6}
        7
        8async1()
        9console.log('3')
        10
        11new Promise(function (resolve{
        12  console.log('4')
        13  resolve()
        14}).then(function () {
        15  console.log('6')
        16})


        1. 首先輸出1, 然后進(jìn)入async1函數(shù),輸出2

        2. await后面雖然是一個(gè)直接量,但是還是先執(zhí)行async函數(shù)外的同步代碼

        1. 輸出3, 進(jìn)入promise輸出4,then回調(diào)進(jìn)入微任務(wù)隊(duì)列

        2. 現(xiàn)在同步代碼執(zhí)行完了, 回到async函數(shù)繼續(xù)執(zhí)行輸出5
          5, 最后運(yùn)行微任務(wù)輸出6


         1async function async1() {
        2  console.log('2')
        3  await async2()
        4  console.log('7')
        5}
        6
        7async function async2() {
        8  console.log('3')
        9}
        10
        11setTimeout(function () {
        12  console.log('8')
        13}, 0)
        14
        15console.log('1')
        16async1()
        17
        18new Promise(function (resolve{
        19  console.log('4')
        20  resolve()
        21}).then(function () {
        22  console.log('6')
        23})
        24console.log('5')


        1. 首先輸出同步代碼1, 然后進(jìn)入async1方法輸出2

        2. 因?yàn)橛龅絘wait所以先進(jìn)群async2方法, 后面的7處于等待狀態(tài)

        1. 在async2中輸出3, 現(xiàn)在跳出async函數(shù)先執(zhí)行外面的同步代碼

        2. 輸出4,5.then回調(diào)進(jìn)入微任務(wù)棧

        1. 現(xiàn)在宏任務(wù)執(zhí)行完了,然后回到async1函數(shù)接著往下執(zhí)行輸出7

        2. 執(zhí)行微任務(wù)輸出6

        1. 進(jìn)入下一輪事件循環(huán)輸出8
          完整輸出:1-2-3-4-5-7-6-8


         1async function async1() {
        2  console.log('2')
        3  const data = await async2()
        4  console.log(data)
        5  console.log('8')
        6}
        7
        8async function async2() {
        9  return new Promise(function (resolve{
        10    console.log('3')
        11    resolve('await的結(jié)果')
        12  }).then(function (data{
        13    console.log('6')
        14    return data
        15  })
        16}
        17console.log('1')
        18
        19setTimeout(function () {
        20  console.log('9')
        21}, 0)
        22
        23async1()
        24
        25new Promise(function (resolve{
        26  console.log('4')
        27  resolve()
        28}).then(function () {
        29  console.log('7')
        30})
        31console.log('5')
        1. 函數(shù)async1和async2只是定義先不管它, 首先輸出1

        2. setTimeout作為宏任務(wù)進(jìn)入宏任務(wù)隊(duì)列等待下一輪事件循環(huán)

        1. 進(jìn)入async1函數(shù)輸出2,await下面的代碼進(jìn)入等待狀態(tài)。

        2. 進(jìn)入async2函數(shù)輸出3,then回調(diào)進(jìn)入微任務(wù)隊(duì)列

        1. 現(xiàn)在執(zhí)行外面的同步代碼, 輸出4,5,then回調(diào)進(jìn)入微任務(wù)隊(duì)列
          6, 按序執(zhí)行微任務(wù),輸出6,7. 現(xiàn)在回到async1函數(shù),
          7, 輸出data, 也就是await關(guān)鍵字等到的內(nèi)容, 接著輸出8
          8, 進(jìn)行下一輪事件循環(huán)輸出9
          執(zhí)行結(jié)果:1-2-3-4-5-6-7-await的結(jié)果-8-9


         1setTimeout(function () {
        2  console.log('8')
        3}, 0)
        4
        5async function async1() {
        6  console.log('1')
        7  const data = await async2()
        8  console.log('6')
        9  return data
        10}
        11
        12async function async2() {
        13  return new Promise(resolve => {
        14    console.log('2')
        15    resolve('async2的結(jié)果')
        16  }).then(data => {
        17    console.log('4')
        18    return data
        19  })
        20}
        21
        22async1().then(data => {
        23  console.log('7')
        24  console.log(data)
        25})
        26
        27new Promise(function (resolve{
        28  console.log('3')
        29  resolve()
        30}).then(function () {
        31  console.log('5')
        32})
        1. setTimeout作為宏任務(wù)進(jìn)入宏任務(wù)隊(duì)列等待下一輪事件循環(huán)

        2. 先執(zhí)行async1函數(shù), 輸出1,然后6進(jìn)入等待狀態(tài),現(xiàn)在執(zhí)行async2

        1. 輸出2, then回調(diào)進(jìn)入微任務(wù)隊(duì)列
          4, 接下來(lái)執(zhí)行外面的同步代碼3, then回調(diào)進(jìn)入微任務(wù)隊(duì)列
          5, 按序列執(zhí)行微任務(wù),輸出4,5. 下面會(huì)帶async1函數(shù)
          6,輸出了4之后執(zhí)行return data, await拿到了內(nèi)容
          7, 繼續(xù)執(zhí)行輸出6, 執(zhí)行了后面的return data才出發(fā)async1的then回調(diào)輸出7以及data
          8, 進(jìn)行第二輪事件循環(huán)輸出8,
          完整輸出結(jié)果:1-2-3-4-5-6-7-async2的結(jié)果-8



        面試題題目一:


         1setTimeout(function() {
        2    console.log('4')
        3})
        4
        5new Promise(function(resolve{
        6    console.log('1'// 同步任務(wù)
        7    resolve()
        8}).then(function() {
        9    console.log('3')
        10})
        11console.log('2')


        輸出結(jié)果:1-2-3-4


         1console.log('1')
        2setTimeout(function() {
        3    console.log('2')
        4    process.nextTick(function() {
        5        console.log('3')
        6    })
        7    new Promise(function(resolve{
        8        console.log('4')
        9        resolve()
        10    }).then(function() {
        11        console.log('5')
        12    })
        13})
        14
        15process.nextTick(function() {
        16    console.log('6')
        17})
        18
        19new Promise(function(resolve{
        20    console.log('7')
        21    resolve()
        22}).then(function() {
        23    console.log('8')
        24})
        25
        26setTimeout(function() {
        27    console.log('9')
        28    process.nextTick(function() {
        29        console.log('10')
        30    })
        31    new Promise(function(resolve{
        32        console.log('11')
        33        resolve()
        34    }).then(function() {
        35        console.log('12')
        36    })


        輸出結(jié)果:
        1-7-6-8-2-4-3-5-9-11-10-12


         1setTimeout(function () {
        2  console.log('6')
        3}, 0)
        4console.log('1')
        5async function async1() {
        6  console.log('2')
        7  await async2()
        8  console.log('5')
        9}
        10async function async2() {
        11  console.log('3')
        12}
        13async1()
        14console.log('4')


        輸出結(jié)果:
        1-2-3-4-5-6


         1console.log('1')
        2async function async1() {
        3  console.log('2')
        4  await 'await的結(jié)果'
        5  console.log('5')
        6}
        7
        8async1()
        9console.log('3')
        10
        11new Promise(function (resolve{
        12  console.log('4')
        13  resolve()
        14}).then(function () {
        15  console.log('6')
        16})


        輸出結(jié)果:1-2-3-4-5-6



        最后聽一首悅耳的歌放松放松,回憶學(xué)到的東西。

        點(diǎn)擊下面16ac0b1d26877fec41139325f50c09c1.webp播放音樂(lè)


        長(zhǎng)按二維碼關(guān)注,一起努力。

        助力尋人啟事

        微信公眾號(hào)回復(fù) 加群 一起學(xué)習(xí)。

        瀏覽 38
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            国产精品电影久久 | 色欲九九| 人少妇精品123在线观看 | 亚洲日韩欧美一区二区天天天 | 俺去啦最新官网 | 91禁 国产 | 农村艳妇疯狂做爰肥水不流外田 | 亚洲精品国产精品国自产观看浪潮 | 国产婷婷成人久久Av免费 | 侵犯双性稚嫩小少爷h视频 |