亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

JavaScript執(zhí)行機(jī)制、事件循環(huán)

rose / 3536人閱讀

摘要:曾經(jīng)的理解首先,是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么為什么不是多線程呢這樣還能提高效率啊假定同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)節(jié)點(diǎn)上編輯了內(nèi)容,而另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器就很懵逼了,到底以執(zhí)行哪個(gè)操作呢所以,設(shè)計(jì)者把

Event Loop曾經(jīng)的理解

首先,JS是單線程語(yǔ)言,也就意味著同一個(gè)時(shí)間只能做一件事,那么

為什么JavaScript不是多線程呢?這樣還能提高效率啊

假定JS同時(shí)有兩個(gè)線程,一個(gè)線程在某個(gè)DOM節(jié)點(diǎn)上編輯了內(nèi)容,而另一個(gè)線程刪除了這個(gè)節(jié)點(diǎn),這時(shí)瀏覽器就很懵逼了,到底以執(zhí)行哪個(gè)操作呢?

所以,設(shè)計(jì)者把JS設(shè)計(jì)成單線程應(yīng)該就很好理解了,為了避免類似上述操作的復(fù)雜性,這一特征將來(lái)也不會(huì)變。

但是單線程有一個(gè)問(wèn)題:一旦這個(gè)線程被阻塞就無(wú)法繼續(xù)工作了,這肯定是不行的

由于異步編程可以實(shí)現(xiàn)“非阻塞”的調(diào)用效果,引入異步編程自然就是順理成章的事情了,那么

JS單線程如何實(shí)現(xiàn)異步的呢?

今天的主咖登場(chǎng)——事件循環(huán)(Event Loop),JS異步是通過(guò)的事件循環(huán)實(shí)現(xiàn)的,理解了Event Loop機(jī)制,就理解
了JS的執(zhí)行機(jī)制。

先來(lái)段代碼:

console.log(1)

setTimeout(()=>{
    console.log(2)
}, 0)

for(let i = 3; i < 10000; i++){
    console.log(i)
}
執(zhí)行結(jié)果:1 3 4 5 6 7 ... 9997 9998 9999 2

setTimeout里的函數(shù)并沒(méi)有立即執(zhí)行,我們都知道這部分叫異步處理模塊,延遲了一段時(shí)間,滿足一定條件后才執(zhí)行

仔細(xì)想想,我們?cè)贘S里通常把任務(wù)分為“同步任務(wù)”和“異步任務(wù)”,它們有以下的執(zhí)行順序:

判斷任務(wù)是同步的還是異步的,如果是同步任務(wù)就進(jìn)入主線程執(zhí)行棧中,如果是異步任務(wù)就進(jìn)入Event Table并注冊(cè)函數(shù),當(dāng)滿足觸發(fā)條件后,進(jìn)入Event Queue

只有等到主線程的同步任務(wù)執(zhí)行完后,才會(huì)去Event Queue中查找是否有可執(zhí)行的異步任務(wù),如有,則進(jìn)入主線程執(zhí)行

以上兩步循環(huán)執(zhí)行,就是所謂的Event Loop,所以上述代碼里:

console.log(1)    是同步任務(wù),進(jìn)入主線程,立即執(zhí)行
setTimeout 是異步任務(wù),進(jìn)入Event Table,0ms后(實(shí)際時(shí)間可能有出入,見(jiàn)注文)進(jìn)入Event Queue,等待進(jìn)入主線程
for 是同步任務(wù),進(jìn)入主線程,立即執(zhí)行
所有主線程任務(wù)執(zhí)行完后,setTimeout從Event Queue進(jìn)入主線程執(zhí)行
*注:HTML5規(guī)范規(guī)定最小延遲時(shí)間不能小于4ms,即x如果小于4,會(huì)被當(dāng)做4來(lái)處理。 不過(guò)不同瀏覽器的實(shí)現(xiàn)不一樣,比如,Chrome可以設(shè)置1ms,IE11/Edge是4ms

這就是我之前對(duì)Event Loop的理解,但是自從看了這篇文章深入理解JS引擎的執(zhí)行機(jī)制顛覆了我對(duì)Event Loop認(rèn)識(shí)三觀,看下面的代碼

Event Loop現(xiàn)在的理解
console.log("start")
setTimeout(()=>{
    console.log("setTimeout")
}, 0)
new Promise((resolve)=>{
    console.log("promise")
    resolve()
}).then(()=>{
    console.log("then")
})
console.log("end")

嘗試按照我們上面的JS執(zhí)行機(jī)制去分析:

console.log("start")是同步任務(wù),進(jìn)入主線程,立即執(zhí)行 setTimeout是異步任務(wù),進(jìn)入Event
Table,滿足觸發(fā)條件后進(jìn)入Event Queue
new Promise是同步任務(wù),進(jìn)入主線程,立即執(zhí)行
.then是異步任務(wù),進(jìn)入Event Table,滿足觸發(fā)條件后進(jìn)入Event Queue,排在Event Queue隊(duì)尾 console.log("end")是同步任務(wù),進(jìn)入主線程,立即執(zhí)行

所以執(zhí)行結(jié)果是:start > promise > end > setTimeout > then

But但是,親自跑了代碼結(jié)果卻是:start > promise > end > then > setTimeout

對(duì)比結(jié)果發(fā)現(xiàn),難道Event Queue里面的順序不是隊(duì)列的先進(jìn)先出的順序嗎?還是這塊執(zhí)行時(shí)有什么改變,事實(shí)就是,前面按照同步和異步任務(wù)劃分的方式并不準(zhǔn)確,那么怎么劃分才是準(zhǔn)確的呢,先看圖(轉(zhuǎn)自谷雨JavaScript 異步、棧、事件循環(huán)、任務(wù)隊(duì)列):

咣咣咣~敲黑板,知識(shí)點(diǎn),知識(shí)點(diǎn),知識(shí)點(diǎn):

Js 中,有兩類任務(wù)隊(duì)列:宏任務(wù)隊(duì)列(macro tasks)和微任務(wù)隊(duì)列(micro tasks)

宏任務(wù)隊(duì)列可以有多個(gè),微任務(wù)隊(duì)列只有一個(gè)。那么什么任務(wù),會(huì)分到哪個(gè)隊(duì)列呢?

宏任務(wù):script(全局任務(wù)), setTimeout, setInterval, setImmediate, I/O, UI rendering.
微任務(wù):process.nextTick, Promise的then或catch, Object.observer, MutationObserver.

那么結(jié)合上面的流程圖和最初理解的執(zhí)行機(jī)制,總結(jié)了一下更為準(zhǔn)確的JS執(zhí)行機(jī)制:

取且僅取一個(gè)宏任務(wù)來(lái)執(zhí)行(第一個(gè)宏任務(wù)就是script任務(wù))。執(zhí)行過(guò)程中判斷是同步還是異步任務(wù),如果是同步任務(wù)就進(jìn)入主線程執(zhí)行棧中,如果是異步任務(wù)就進(jìn)入異步處理模塊,這些異步處理模塊的任務(wù)當(dāng)滿足觸發(fā)條件后,進(jìn)入任務(wù)隊(duì)列,進(jìn)入任務(wù)隊(duì)列后,按照宏任務(wù)和微任務(wù)進(jìn)行劃分,劃分完畢后,執(zhí)行下一步。

如果微任務(wù)隊(duì)列不為空,則依次取出微任務(wù)來(lái)執(zhí)行,直到微任務(wù)隊(duì)列為空(即當(dāng)前l(fā)oop所有微任務(wù)執(zhí)行完),執(zhí)行下一步。

進(jìn)入下一輪loop或更新UI渲染。

Event Loop就是循環(huán)執(zhí)行上面三步,接下來(lái)使用上面的結(jié)論分析個(gè)例子幫助理解

微任務(wù)里嵌套宏任務(wù)

console.log("第一輪");

setTimeout(() => {                    //為了便于敘述時(shí)區(qū)分,標(biāo)記為 setTimeout1
    console.log("第二輪");
    Promise.resolve().then(() => {    //為了便于敘述時(shí)區(qū)分,標(biāo)記為 then1
        console.log("A");
    })
}, 0);

setTimeout(() => {                    //為了便于敘述時(shí)區(qū)分,標(biāo)記為 setTimeout2
    console.log("第三輪");
    console.log("B");
}, 0);

new Promise((resolve)=>{              //為了便于敘述時(shí)區(qū)分,標(biāo)記為 Promise1
    console.log("C")
    resolve()
}).then(() => {                       //為了便于敘述時(shí)區(qū)分,標(biāo)記為 then2
    Promise.resolve().then(() => {    //為了便于敘述時(shí)區(qū)分,標(biāo)記為 then3
        console.log("D")
        setTimeout(() => {            //為了便于敘述時(shí)區(qū)分,標(biāo)記為 setTimeout3
            console.log("第四輪");
            console.log("E");
        }, 0);
    });
});

執(zhí)行結(jié)果:第一輪 > C > D > 第二輪 > A > 第三輪 > B > 第四輪 > E

分析:

loop1:
第一步:首先執(zhí)行全局宏任務(wù),里面同步任務(wù)有下面兩個(gè),都立即進(jìn)入主線程執(zhí)行完后出棧

1.console.log("第一輪")
2.Promise1

輸出 “第一輪” > “C”

異步任務(wù)有三個(gè),分別進(jìn)入相應(yīng)的任務(wù)隊(duì)列:

1.setTimeout1,該任務(wù)按照劃分標(biāo)準(zhǔn)是 宏任務(wù)

setTimeout(() => {
    console.log("第二輪");
    Promise.resolve().then(() => {
        console.log("A");
    })
}, 0);
2.setTimeout2,該任務(wù)按照劃分標(biāo)準(zhǔn)是 宏任務(wù)

setTimeout(() => {
    console.log("第三輪");
    console.log("B");
}, 0);
3.then2,該任務(wù)按照劃分標(biāo)準(zhǔn)是 微任務(wù)

.then(() => {
    Promise.resolve().then(() => {
        console.log("D")
        setTimeout(() => {
            console.log("第四輪");
            console.log("E");
        }, 0);
    });
});
所以此時(shí)宏任務(wù)隊(duì)列為: setTimeout1,setTimeout2
微任務(wù)隊(duì)列為: then2

第二步:loop1 微任務(wù)隊(duì)列不為空,then2出隊(duì)列并執(zhí)行,然后這個(gè)微任務(wù)里的 then3繼續(xù)進(jìn)入微任務(wù)隊(duì)列 ,setTimeout3進(jìn)入宏任務(wù)隊(duì)列隊(duì)尾

那么此時(shí)微任務(wù)隊(duì)列為: then3  
宏任務(wù)隊(duì)列為:setTimeout1,setTimeout2,setTimeout3

但是此時(shí)第二步并沒(méi)有完,因?yàn)槲⑷蝿?wù)隊(duì)列只要不為空,就一直執(zhí)行當(dāng)前l(fā)oop的微任務(wù),所以從微任務(wù)隊(duì)列取出 then3 執(zhí)行輸出 “D”

此時(shí)微任務(wù)隊(duì)列為:   
宏任務(wù)隊(duì)列為:setTimeout1,setTimeout2,setTimeout3

到目前為止,當(dāng)前l(fā)oop的微任務(wù)對(duì)列為空,進(jìn)入下一個(gè)loop,輸出情況是“第一輪” > “C” > “D”

loop2:
第一步:在宏任務(wù)隊(duì)列隊(duì)首里取出一個(gè)任務(wù)執(zhí)行,即setTimeout1執(zhí)行輸出“第二輪”,并then1進(jìn)入微任務(wù)隊(duì)列

此時(shí)微任務(wù)隊(duì)列為: then1  
宏任務(wù)隊(duì)列為:setTimeout2,setTimeout3

第二步:loop2 微任務(wù)隊(duì)列不為空,則從微任務(wù)隊(duì)列取出then1執(zhí)行,輸出“A”

此時(shí)微任務(wù)隊(duì)列為:  
宏任務(wù)隊(duì)列為:setTimeout2,setTimeout3

到目前為止,當(dāng)前l(fā)oop的微任務(wù)對(duì)列為空,進(jìn)入下一個(gè)loop,輸出情況是“第一輪” > “C” > “D” > “第二輪” > “A”

loop3:
第一步:在宏任務(wù)隊(duì)列隊(duì)首里取出一個(gè)任務(wù)執(zhí)行,即setTimeout2執(zhí)行輸出“第三輪” > “B”

此時(shí)微任務(wù)隊(duì)列為:   
宏任務(wù)隊(duì)列為:setTimeout3

第二步:由于loop3 微任務(wù)隊(duì)列為空,則直接進(jìn)入下一輪loop,輸出情況是“第一輪” > “C” > “D” > “第二輪” > “A” > “第三輪” > “B”

loop4:
第一步:在宏任務(wù)隊(duì)列隊(duì)首里取出一個(gè)任務(wù)執(zhí)行,即setTimeout3執(zhí)行輸出“第四輪” > “E”

此時(shí)微任務(wù)隊(duì)列為:   
宏任務(wù)隊(duì)列為:

第二步:由于loop4 微任務(wù)隊(duì)列為空,宏任務(wù)隊(duì)列也為空,則此次Event Loop結(jié)束,最終輸出情況是“第一輪” > “C” > “D” > “第二輪” > “A” > “第三輪” > “B” > “第四輪” > “E”

上面的整個(gè)過(guò)程就是更為準(zhǔn)確的Event Loop,下面還有個(gè)不同的例子供讀者自行嘗試

宏任務(wù)里嵌套微任務(wù)

console.log("第一輪");

setTimeout(() => {
    console.log("第二輪");
    Promise.resolve().then(() => {
        console.log("A");
    })
}, 0);

setTimeout(() => {
    console.log("第三輪");
    console.log("B");
}, 0);

new Promise((resolve) => {
    console.log("C")
    resolve()
}).then(() => {                        //注意,這個(gè)函數(shù)改動(dòng)啦
    setTimeout(() => {
        console.log("第四輪");
        console.log("E");
        Promise.resolve().then(() => {
            console.log("D")
        });
    }, 0);
});

執(zhí)行結(jié)果:第一輪 > C > 第二輪 > A > 第三輪 > B > 第四輪 > E > D

Links:

深入理解JS引擎的執(zhí)行機(jī)制
JavaScript 異步、棧、事件循環(huán)、任務(wù)隊(duì)列
JavaScript 運(yùn)行機(jī)制詳解:深入理解Event Loop
JavaScript:并發(fā)模型與Event Loop
JavaScript 運(yùn)行機(jī)制詳解:再談Event Loop[阮一峰]

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/92709.html

相關(guān)文章

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

    摘要:主線程不斷重復(fù)上面的三步,此過(guò)程也就是常說(shuō)的事件循環(huán)。所以主線程代碼執(zhí)行時(shí)間過(guò)長(zhǎng),會(huì)阻塞事件循環(huán)的執(zhí)行。參考資料這一次,徹底弄懂執(zhí)行機(jī)制任務(wù)隊(duì)列的順序機(jī)制事件循環(huán)搞懂異步事件輪詢與中的事件循環(huán) 1. 說(shuō)明 讀過(guò)本文章后,您能知道: JavaScript代碼在瀏覽器中的執(zhí)行機(jī)制和事件循環(huán) 面試中經(jīng)常遇到的代碼輸出順序問(wèn)題 首先通過(guò)一段代碼來(lái)驗(yàn)證你是否了解代碼輸出順序,如果你不知道輸出...

    Ververica 評(píng)論0 收藏0
  • JavaScript 運(yùn)行機(jī)制詳解(理解同步、異步和事件循環(huán))

    摘要:從異步過(guò)程的角度看,函數(shù)就是異步過(guò)程的發(fā)起函數(shù),事件監(jiān)聽(tīng)函數(shù)就是異步過(guò)程的回調(diào)函數(shù)。事件觸發(fā)時(shí),表示異步任務(wù)完成,會(huì)將事件監(jiān)聽(tīng)器函數(shù)封裝成一條消息放到消息隊(duì)列中,等待主線程執(zhí)行。 1.為什么JavaScript是單線程? JavaScript語(yǔ)言的一大特點(diǎn)就是單線程,也就是說(shuō),同一個(gè)時(shí)間只能做一件事。那么,為什么JavaScript不能有多個(gè)線程呢?這樣能提高效率啊。JavaScrip...

    loonggg 評(píng)論0 收藏0
  • Javascript系列之javascript機(jī)制

    摘要:異步任務(wù)必須指定回調(diào)函數(shù),當(dāng)異步任務(wù)從任務(wù)隊(duì)列回到執(zhí)行棧,回調(diào)函數(shù)就會(huì)執(zhí)行。事件循環(huán)主線程從任務(wù)隊(duì)列中讀取事件,這個(gè)過(guò)程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為。事件循環(huán)事件循環(huán)是指主線程重復(fù)從消息隊(duì)列中取消息執(zhí)行的過(guò)程。 參考鏈接:這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制https://zhuanlan.zhihu.com/p/...從瀏覽器多進(jìn)程到JS單線程,JS運(yùn)行機(jī)制...

    13651657101 評(píng)論0 收藏0
  • JS瀏覽器事件循環(huán)機(jī)制

    摘要:事件循環(huán)機(jī)制事件循環(huán)機(jī)制分為瀏覽器和事件循環(huán)機(jī)制,兩者的實(shí)現(xiàn)技術(shù)不一樣,瀏覽器是中定義的規(guī)范,是由庫(kù)實(shí)現(xiàn)。整個(gè)事件循環(huán)完成之后,會(huì)去檢測(cè)微任務(wù)的任務(wù)隊(duì)列中是否存在任務(wù),存在就執(zhí)行。 文章來(lái)自我的 github 博客,包括技術(shù)輸出和學(xué)習(xí)筆記,歡迎star。 先來(lái)明白些概念性內(nèi)容。 進(jìn)程、線程 進(jìn)程是系統(tǒng)分配的獨(dú)立資源,是 CPU 資源分配的基本單位,進(jìn)程是由一個(gè)或者多個(gè)線程組成的。 線...

    zebrayoung 評(píng)論0 收藏0
  • 瀏覽器中的事件循環(huán)機(jī)制

    摘要:?jiǎn)尉€程的話,如果我們做一些的操作比如說(shuō)這是一個(gè)耗時(shí)的操所那么在這將近一秒內(nèi),線程就會(huì)被阻塞,無(wú)法繼續(xù)執(zhí)行下面的任務(wù)。事件循環(huán)的主要機(jī)制就是任務(wù)隊(duì)列機(jī)制一個(gè)事件循環(huán)有一個(gè)或者多個(gè)任務(wù)隊(duì)列。 瀏覽器中的事件循環(huán)機(jī)制 網(wǎng)上一搜事件循環(huán), 很多文章標(biāo)題的前面會(huì)加上 JavaScript, 但是我覺(jué)得事件循環(huán)機(jī)制跟 JavaScript 沒(méi)什么關(guān)系, JavaScript 只是一門(mén)解釋型語(yǔ)言, ...

    zzbo 評(píng)論0 收藏0
  • 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制

    摘要:事件完成,回調(diào)函數(shù)進(jìn)入。主線程從讀取回調(diào)函數(shù)并執(zhí)行。終于執(zhí)行完了,終于從進(jìn)入了主線程執(zhí)行。遇到,立即執(zhí)行。宏任務(wù)微任務(wù)第三輪事件循環(huán)宏任務(wù)執(zhí)行結(jié)束,執(zhí)行兩個(gè)微任務(wù)和。事件循環(huán)事件循環(huán)是實(shí)現(xiàn)異步的一種方法,也是的執(zhí)行機(jī)制。 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,可以揍我。不論你是javascript新手還是老鳥(niǎo),不論是面試求職,還是日常開(kāi)發(fā)工作...

    dreambei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<