<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 18835字,需瀏覽 38分鐘

           ·

          2021-07-31 03:22

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


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

          1.JavaScript是一門單線程語言。

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


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


           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是一門單線程語言,在最新的HTML5中提出了Web-Worker, 但javascript是單線程這一核心扔未改變。所以一切javascript版的“多線程”都是用單線程模擬出來的,一切javascript多線程都是紙老虎


          JS為什么是單線程的

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


          js為什么需要異步

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


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

          js中的異步以及多線程都可以理解成為一種“假象”,就拿h5的WebWorker來說,子線程有諸多限制,不能控制DOM,不能修改全局對象等等,通常只用來做計(jì)算做數(shù)據(jù)處理。
          這些限制并沒有違背我們之前的觀點(diǎn),所以說是“假象”。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ù)語其實(shí)說的是同一個(gè)東西
          “先執(zhí)行同步操作異步操作排在事件隊(duì)列里”這樣的理解其實(shí)也沒有任何問題但如果深入的話會(huì)引出很多其他概念,比如event table和event queue, 我們來看運(yùn)行過程:

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

          2. 異步任務(wù)在event table中注冊事件,當(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,注冊回調(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, 注冊的事件就是它的回調(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)行過程:

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

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

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


          上述流程走完,我們知道setTimeout這個(gè)函數(shù),是經(jīng)過指定時(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í)間將注冊的函數(shù)置入event queue,不是每過ms會(huì)執(zhí)行一次fn,而是每過ms秒,會(huì)有fn進(jìn)入event queue。需要注意一點(diǎn)的是,一旦setIntval的回調(diào)函數(shù)fn執(zhí)行時(shí)間超過了延遲事件ms,那么就完成看不出來有時(shí)間間隔了。


          除了廣義的同步任務(wù)和異步任務(wù),我們對任務(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)入對應(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í)行的,然后注冊then回調(diào)。注冊完之后,繼續(xù)往下執(zhí)行同步代碼,在這之前,then的回調(diào)不會(huì)執(zhí)行。同步代碼塊執(zhí)行完畢后,才會(huì)在事件循環(huán)中檢測是否有可用的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ù)來運(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ù)..


          下面用代碼來深入理解上面的機(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ù)注冊后分發(fā)到宏任務(wù)event queue.

          3. 接下來遇到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對應(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, 接下來遇到了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(請注意,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ù)都對應(yīng)會(huì)有一個(gè)微任務(wù)棧,宏任務(wù)在執(zhí)行過程中會(huì)先執(zhí)行同步代碼再執(zhí)行微任務(wù)棧。


          async/await是什么

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


          async/await用來干什么

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


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

          async函數(shù)會(huì)返回一個(gè)Promise對象,如果在函數(shù)中return一個(gè)直接量(普通變量),async會(huì)把這個(gè)直接量通過Promise.resolve()封裝成Promise對象。如果你返回了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對象,await它會(huì)'阻塞'后面的diamante,等著promise對象resolve, 然后得到resolve的值作為await表達(dá)式的運(yùn)算結(jié)果。但是此"阻塞"非彼“阻塞”,這就是await必須用在async函數(shù)中的原因。async函數(shù)調(diào)用不會(huì)造成"阻塞",它內(nèi)部所有的“阻塞”都被封裝在一個(gè)promise對象中異步執(zhí)行(這里的阻塞理解成異步等待更合理)


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

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


          async/await在什么場景使用

          單一的promise鏈并不能發(fā)現(xiàn)async/await的優(yōu)勢,但是如果需要處理由多個(gè)promise組成的then鏈的時(shí)候,優(yōu)勢就能體現(xiàn)出來了(Promise通過then鏈來解決多層回調(diào)的問題,現(xiàn)在又用async/awai來進(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 來實(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)部有語法錯(cuò)誤會(huì)觸發(fā)catch方法
          36})


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

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

          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右邊的語句會(huì)被立即執(zhí)行然后await下面的代碼進(jìn)入等待狀態(tài),等待await得到結(jié)果。await后面如果不是promise對象,await會(huì)阻塞后面的代碼,先執(zhí)行async外面的同步代碼,同步代碼執(zhí)行完,再回到async內(nèi)部,把這個(gè)非promise的東西,作為await表達(dá)式的結(jié)果。await后面如果是promise對象,await也會(huì)暫停async后面的代碼,先執(zhí)行async外面的同步代碼,等著promise對象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


          測試代碼的輸出結(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, 接下來執(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播放音樂


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

          助力尋人啟事

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

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

          手機(jī)掃一掃分享

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

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  青青草视频在线网站 | 四虎成人网 | 欧美一级操逼网 | 人妻少妇无码精品 | 又粗又大又黄又爽无遮挡 |