国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

徹底搞懂瀏覽器Event-loop

source / 3069人閱讀

摘要:檢查宏任務(wù)隊(duì)列,發(fā)現(xiàn)有的回調(diào)函數(shù)立即執(zhí)行回調(diào)函數(shù)輸出。接著遇到它的作用是在后將回調(diào)函數(shù)放到宏任務(wù)隊(duì)列中這個(gè)任務(wù)在再下一次的事件循環(huán)中執(zhí)行。

為什么會(huì)寫(xiě)這篇博文呢?

前段時(shí)間,和頭條的小伙伴聊天問(wèn)頭條面試前端會(huì)問(wèn)哪些問(wèn)題,他稱(chēng)如果是他面試的話,event-loop肯定是要問(wèn)的。那天聊了蠻多,event-loop算是給我留下了很深的印象,原因很簡(jiǎn)單,因?yàn)橹拔覐奈瓷钊肓私膺^(guò),如果是面試的時(shí)候,我遇到了這個(gè)問(wèn)題,估計(jì)回答得肯定不如人意。

因此,最近我閱讀了一些相關(guān)的文章,并細(xì)細(xì)梳理了一番,輸出了本篇博文,希望能幫助大家搞懂瀏覽器的event-loop。后續(xù)會(huì)補(bǔ)充node中的event-loop。

1. 預(yù)備知識(shí)
JavaScript的運(yùn)行機(jī)制:

(1)所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧(execution context stack)。

(2)主線程之外,還存在"任務(wù)隊(duì)列"(task queue)。只要異步任務(wù)有了運(yùn)行結(jié)果,就在"任務(wù)隊(duì)列"之中放置一個(gè)事件。

(3)一旦"執(zhí)行棧"中的所有同步任務(wù)執(zhí)行完畢,系統(tǒng)就會(huì)讀取"任務(wù)隊(duì)列",看看里面有哪些事件。那些對(duì)應(yīng)的異步任務(wù),于是結(jié)束等待狀態(tài),進(jìn)入執(zhí)行棧,開(kāi)始執(zhí)行。

(4)主線程不斷重復(fù)上面的第三步

概括即是: 調(diào)用棧中的同步任務(wù)都執(zhí)行完畢,棧內(nèi)被清空了,就代表主線程空閑了,這個(gè)時(shí)候就會(huì)去任務(wù)隊(duì)列中按照順序讀取一個(gè)任務(wù)放入到棧中執(zhí)行。每次棧內(nèi)被清空,都會(huì)去讀取任務(wù)隊(duì)列有沒(méi)有任務(wù),有就讀取執(zhí)行,一直循環(huán)讀取-執(zhí)行的操作

一個(gè)事件循環(huán)中有一個(gè)或者是多個(gè)任務(wù)隊(duì)列
JavaScript中有兩種異步任務(wù):

宏任務(wù): script(整體代碼), setTimeout, setInterval, setImmediate, I/O, UI rendering

微任務(wù): process.nextTick(Nodejs), Promises, Object.observe, MutationObserver;

2. 事件循環(huán)(event-loop)是什么?

主線程從"任務(wù)隊(duì)列"中讀取執(zhí)行事件,這個(gè)過(guò)程是循環(huán)不斷的,這個(gè)機(jī)制被稱(chēng)為事件循環(huán)。此機(jī)制具體如下:主線程會(huì)不斷從任務(wù)隊(duì)列中按順序取任務(wù)執(zhí)行,每執(zhí)行完一個(gè)任務(wù)都會(huì)檢查microtask隊(duì)列是否為空(執(zhí)行完一個(gè)任務(wù)的具體標(biāo)志是函數(shù)執(zhí)行棧為空),如果不為空則會(huì)一次性執(zhí)行完所有microtask。然后再進(jìn)入下一個(gè)循環(huán)去任務(wù)隊(duì)列中取下一個(gè)任務(wù)執(zhí)行。

詳細(xì)說(shuō)明:

選擇當(dāng)前要執(zhí)行的宏任務(wù)隊(duì)列,選擇一個(gè)最先進(jìn)入任務(wù)隊(duì)列的宏任務(wù),如果沒(méi)有宏任務(wù)可以選擇,則會(huì)跳轉(zhuǎn)至microtask的執(zhí)行步驟。

將事件循環(huán)的當(dāng)前運(yùn)行宏任務(wù)設(shè)置為已選擇的宏任務(wù)。

運(yùn)行宏任務(wù)。

將事件循環(huán)的當(dāng)前運(yùn)行任務(wù)設(shè)置為null。

將運(yùn)行完的宏任務(wù)從宏任務(wù)隊(duì)列中移除。

microtasks步驟:進(jìn)入microtask檢查點(diǎn)。

更新界面渲染。

返回第一步。

執(zhí)行進(jìn)入microtask檢查的的具體步驟如下:

設(shè)置進(jìn)入microtask檢查點(diǎn)的標(biāo)志為true。

當(dāng)事件循環(huán)的微任務(wù)隊(duì)列不為空時(shí):選擇一個(gè)最先進(jìn)入microtask隊(duì)列的microtask;設(shè)置事件循環(huán)的當(dāng)前運(yùn)行任務(wù)為已選擇的microtask;運(yùn)行microtask;設(shè)置事件循環(huán)的當(dāng)前運(yùn)行任務(wù)為null;將運(yùn)行結(jié)束的microtask從microtask隊(duì)列中移除。

對(duì)于相應(yīng)事件循環(huán)的每個(gè)環(huán)境設(shè)置對(duì)象(environment settings object),通知它們哪些promise為rejected。

清理indexedDB的事務(wù)。

設(shè)置進(jìn)入microtask檢查點(diǎn)的標(biāo)志為false。

需要注意的是:當(dāng)前執(zhí)行棧執(zhí)行完畢時(shí)會(huì)立刻先處理所有微任務(wù)隊(duì)列中的事件,然后再去宏任務(wù)隊(duì)列中取出一個(gè)事件。同一次事件循環(huán)中,微任務(wù)永遠(yuǎn)在宏任務(wù)之前執(zhí)行。

圖示:

3. Event-loop 是如何工作的?

先看一個(gè)簡(jiǎn)單的示例:

setTimeout(()=>{
    console.log("setTimeout1");
    Promise.resolve().then(data => {
        console.log(222);
    });
});
setTimeout(()=>{
    console.log("setTimeout2");
});
Promise.resolve().then(data=>{
    console.log(111);
});

思考一下, 運(yùn)行結(jié)果是什么?

運(yùn)行結(jié)果為:

111
setTimeout1
222
setTimeout2

我們來(lái)看一下為什么?

我們來(lái)詳細(xì)說(shuō)明一下, JS引擎是如何執(zhí)行這段代碼的:

主線程上沒(méi)有需要執(zhí)行的代碼

接著遇到setTimeout 0,它的作用是在 0ms 后將回調(diào)函數(shù)放到宏任務(wù)隊(duì)列中(這個(gè)任務(wù)在下一次的事件循環(huán)中執(zhí)行)。

接著遇到setTimeout 0,它的作用是在 0ms 后將回調(diào)函數(shù)放到宏任務(wù)隊(duì)列中(這個(gè)任務(wù)在再下一次的事件循環(huán)中執(zhí)行)。

首先檢查微任務(wù)隊(duì)列, 即 microtask隊(duì)列,發(fā)現(xiàn)此隊(duì)列不為空,執(zhí)行第一個(gè)promise的then回調(diào),輸出 "111"。

此時(shí)microtask隊(duì)列為空,進(jìn)入下一個(gè)事件循環(huán), 檢查宏任務(wù)隊(duì)列,發(fā)現(xiàn)有 setTimeout的回調(diào)函數(shù),立即執(zhí)行回調(diào)函數(shù)輸出 "setTimeout1",檢查microtask 隊(duì)列,發(fā)現(xiàn)隊(duì)列不為空,執(zhí)行promise的then回調(diào),輸出"222",microtask隊(duì)列為空,進(jìn)入下一個(gè)事件循環(huán)。

檢查宏任務(wù)隊(duì)列,發(fā)現(xiàn)有 setTimeout的回調(diào)函數(shù), 立即執(zhí)行回調(diào)函數(shù)輸出"setTimeout2"。

再思考一下下面代碼的執(zhí)行順序:

console.log("script start");

setTimeout(function () {
    console.log("setTimeout---0");
}, 0);

setTimeout(function () {
    console.log("setTimeout---200");
    setTimeout(function () {
        console.log("inner-setTimeout---0");
    });
    Promise.resolve().then(function () {
        console.log("promise5");
    });
}, 200);

Promise.resolve().then(function () {
    console.log("promise1");
}).then(function () {
    console.log("promise2");
});
Promise.resolve().then(function () {
    console.log("promise3");
});
console.log("script end");

思考一下,運(yùn)行結(jié)果是什么?

運(yùn)行結(jié)果為:

script start
script end
promise1
promise3
promise2
setTimeout---0
setTimeout---200
promise5
inner-setTimeout---0

那么為什么?

我們來(lái)詳細(xì)說(shuō)明一下,JS引擎是如何執(zhí)行這段代碼的:

首先順序執(zhí)行完主進(jìn)程上的同步任務(wù),第一句和最后一句的console.log

接著遇到setTimeout 0,它的作用是在 0ms 后將回調(diào)函數(shù)放到宏任務(wù)隊(duì)列中(這個(gè)任務(wù)在下一次的事件循環(huán)中執(zhí)行)。

接著遇到setTimeout 200,它的作用是在 200ms 后將回調(diào)函數(shù)放到宏任務(wù)隊(duì)列中(這個(gè)任務(wù)在再下一次的事件循環(huán)中執(zhí)行)。

同步任務(wù)執(zhí)行完之后,首先檢查微任務(wù)隊(duì)列,即 microtask隊(duì)列, 發(fā)現(xiàn)此隊(duì)列不為空,執(zhí)行第一個(gè)promise的then回調(diào),輸出 "promise1",然后執(zhí)行第二個(gè)promise的then回調(diào),輸出"promise3",由于第一個(gè)promise的.then()的返回依然是promise,所以第二個(gè).then()會(huì)放到microtask隊(duì)列繼續(xù)執(zhí)行,輸出 "promise2";

此時(shí)microtask隊(duì)列為空,進(jìn)入下一個(gè)事件循環(huán),檢查宏任務(wù)隊(duì)列,發(fā)現(xiàn)有 setTimeout的回調(diào)函數(shù),立即執(zhí)行回調(diào)函數(shù)輸出 "setTimeout---0",檢查microtask 隊(duì)列,隊(duì)列為空,進(jìn)入下一次事件循環(huán).

檢查宏任務(wù)隊(duì)列,發(fā)現(xiàn)有 setTimeout的回調(diào)函數(shù),立即執(zhí)行回調(diào)函數(shù)輸出"setTimeout---200".

接著遇到setTimeout 0,它的作用是在 0ms 后將回調(diào)函數(shù)放到宏任務(wù)隊(duì)列中,檢查微任務(wù)隊(duì)列,即 microtask 隊(duì)列, 發(fā)現(xiàn)此隊(duì)列不為空,執(zhí)行promise的then回調(diào),輸出"promise5"。

此時(shí)microtask隊(duì)列為空,進(jìn)入下一個(gè)事件循環(huán),檢查宏任務(wù)隊(duì)列,發(fā)現(xiàn)有 setTimeout 的回調(diào)函數(shù),立即執(zhí)行回調(diào)函數(shù)輸出,輸出"inner-setTimeout---0".代碼執(zhí)行結(jié)束.

4. 為什么會(huì)需要event-loop?

因?yàn)?JavaScript 是單線程的。單線程就意味著,所有任務(wù)需要排隊(duì),前一個(gè)任務(wù)結(jié)束,才會(huì)執(zhí)行后一個(gè)任務(wù)。如果前一個(gè)任務(wù)耗時(shí)很長(zhǎng),后一個(gè)任務(wù)就不得不一直等著。為了協(xié)調(diào)事件(event),用戶交互(user interaction),腳本(script),渲染(rendering),網(wǎng)絡(luò)(networking)等,用戶代理(user agent)必須使用事件循環(huán)(event loops)。

5. 參考文章:

https://segmentfault.com/a/11...

https://segmentfault.com/a/11...

https://segmentfault.com/a/11...

http://www.ruanyifeng.com/blo...

謝謝您花費(fèi)寶貴的時(shí)間閱讀本文,如果本文給了您一點(diǎn)幫助或者是啟發(fā),那么不要吝嗇你的贊和Star哈,您的肯定是我前進(jìn)的最大動(dòng)力。https://github.com/YvetteLau/...

關(guān)注小姐姐的公眾號(hào),和小姐姐一起學(xué)前端。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/101761.html

相關(guān)文章

  • 最后一次搞懂 Event Loop

    摘要:由于是單線程的,這些方法就會(huì)按順序被排列在一個(gè)單獨(dú)的地方,這個(gè)地方就是所謂執(zhí)行棧。事件隊(duì)列每次僅執(zhí)行一個(gè)任務(wù),在該任務(wù)執(zhí)行完畢之后,再執(zhí)行下一個(gè)任務(wù)。 Event Loop 是 JavaScript 異步編程的核心思想,也是前端進(jìn)階必須跨越的一關(guān)。同時(shí),它又是面試的必考點(diǎn),特別是在 Promise 出現(xiàn)之后,各種各樣的面試題層出不窮,花樣百出。這篇文章從現(xiàn)實(shí)生活中的例子入手,讓你徹底理解 E...

    gself 評(píng)論0 收藏0
  • 徹底搞懂 defer & async

    摘要:徹底搞懂通過(guò)瀏覽器的開(kāi)發(fā)者工具可以直觀的看到,圖中藍(lán)色的線和藍(lán)色的字使用不同的表現(xiàn)形式表示這個(gè)事件觸發(fā)的時(shí)間。當(dāng)腳本下載完后立即執(zhí)行,執(zhí)行順序不確定。 徹底搞懂 defer & async DOMContentLoaded showImg(https://segmentfault.com/img/remote/1460000013480394?w=1309&h=879); 通過(guò) chr...

    luckyyulin 評(píng)論0 收藏0
  • 徹底搞懂JavaScript執(zhí)行機(jī)制

    摘要:徹底搞懂執(zhí)行機(jī)制首先我們大家都了解的是,是一門(mén)單線程語(yǔ)言,所以我們就可以得出是按照語(yǔ)句順序執(zhí)行的首先看這個(gè)顯然大家都知道結(jié)果,依次輸出,然而換一種這個(gè)時(shí)候再看代碼的順序執(zhí)行,輸出,,,。不過(guò)即使主線程為空,也是達(dá)不到的,根據(jù)標(biāo)準(zhǔn),最低是。 徹底搞懂JavaScript執(zhí)行機(jī)制 首先我們大家都了解的是,JavaScript 是一門(mén)單線程語(yǔ)言,所以我們就可以得出: JavaScript 是...

    hizengzeng 評(píng)論0 收藏0
  • 徹底搞懂路由跳轉(zhuǎn):location 和 history 接口

    摘要:在單頁(yè)應(yīng)用中,通常由前端來(lái)配置路由,根據(jù)不同的顯示不同的內(nèi)容。接口是新增的,它有五個(gè)方法可以改變而不刷新頁(yè)面。事件能監(jiān)聽(tīng)除和外的變化。而模式下,我們不僅要在事件回調(diào)里處理的變化,還需要分別在和方法里處理的變化。 在單頁(yè)應(yīng)用中,通常由前端來(lái)配置路由,根據(jù)不同的 url 顯示不同的內(nèi)容。想要知道這是如何做到的,首先得了解瀏覽器提供的兩大 API: window.location lo...

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

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

0條評(píng)論

閱讀需要支付1元查看
<