成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

面試題之Event Loop終極篇

233jl / 2741人閱讀

摘要:下面開(kāi)始分析開(kāi)頭的代碼第一輪事件循環(huán)流程整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時(shí)不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務(wù)中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)中。

先上一道常見(jiàn)的筆試題

console.log("1");
async function async1() {
    console.log("2");
    await async2();
    console.log("3");
}
async function async2() {
    console.log("4");
}

process.nextTick(function() {
    console.log("5");
})

setTimeout(function() {
    console.log("6");
    process.nextTick(function() {
        console.log("7");
    })
    new Promise(function(resolve) {
        console.log("8");
        resolve();
    }).then(function() {
        console.log("9")
    })
})

async1();

new Promise(function(resolve) {
    console.log("10");
    resolve();
}).then(function() {
    console.log("11");
});
console.log("12");

大家可以先配合下面這個(gè)圖片思考一下輸出順序及這么運(yùn)行的原因

上面簡(jiǎn)化圖解可拆分為三部分:

一、JavaScript引擎

*Memory Heap 內(nèi)存堆 —— 這是內(nèi)存發(fā)生分配的地方

*Call Stack 調(diào)用棧 —— 這是代碼運(yùn)行時(shí)棧幀存放的位置

二、Runtime 運(yùn)行時(shí)

我們要知道的是,像setTimeOut DOM AJAX,都不是由JavaScript引擎提供,而是由瀏覽器提供,統(tǒng)稱(chēng)為Web APIs

三、EventLoop
1、關(guān)于javascript

javascript是一門(mén)單線程語(yǔ)言,雖然HTML5提出了Web-works這樣的多線程解決方案,但是并沒(méi)有改變JaveScript是單線程的本質(zhì)。

什么是H5 Web Works?

就是將一些大計(jì)算量的代碼交由web Worker運(yùn)行而不凍結(jié)用戶(hù)界面,但是子線程完全受主線程控制,且不得操作DOM。所以,這個(gè)新標(biāo)準(zhǔn)并沒(méi)有改變JavaScript單線程的本質(zhì)

2、javascript事件循環(huán)

既然js是單線程的,就是同一時(shí)間只能做一件事情。那么問(wèn)題來(lái)了,我們?cè)L問(wèn)一個(gè)頁(yè)面,這個(gè)頁(yè)面的初始化代碼運(yùn)行時(shí)間很長(zhǎng),比如有很多圖片、視頻、外部資源等等,難道我們也要一直在那等著嗎?答案當(dāng)然是 不能

所以就出現(xiàn)了兩類(lèi)任務(wù):

同步任務(wù)

異步任務(wù)

同步和異步任務(wù)分別進(jìn)入不同的 "‘場(chǎng)所"’ 執(zhí)行。所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧;而異步任務(wù)進(jìn)入Event Table并注冊(cè)回調(diào)函數(shù)

當(dāng)這個(gè)異步任務(wù)有了運(yùn)行結(jié)果,Event Table會(huì)將這個(gè)回調(diào)函數(shù)移入Event Queue,進(jìn)入等待狀態(tài)

當(dāng)主線程內(nèi)同步任務(wù)執(zhí)行完成,會(huì)去Event Queue讀取對(duì)應(yīng)的函數(shù),并結(jié)束它的等待狀態(tài),進(jìn)入主線程執(zhí)行

主線程不斷重復(fù)上面3個(gè)步驟,也就是常說(shuō)的Event Loop(事件循環(huán))。

那么我們?cè)趺粗朗裁磿r(shí)候主線程是空的呢?

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

3、setTimeout和setInterval

setTimeout(fn,0)這里的延遲0秒時(shí)什么意思呢?

含義是,當(dāng)主線程執(zhí)行棧內(nèi)為空時(shí),不用等待,就馬上執(zhí)行。

setInterval和setTimeout類(lèi)似,只是前者是循環(huán)的執(zhí)行。對(duì)于執(zhí)行順序來(lái)說(shuō),setInterval會(huì)每隔指定的時(shí)間將注冊(cè)的函數(shù)置入Event Queue,如果前面的任務(wù)耗時(shí)太久,那么同樣需要等待。

對(duì)于setInterval(fn,ms)來(lái)說(shuō),我們已經(jīng)知道不是每過(guò)ms秒會(huì)執(zhí)行一次fn,而是每過(guò)ms秒,會(huì)有fn進(jìn)入Event Queue。一旦setInterval的回調(diào)函數(shù)fn執(zhí)行時(shí)間超過(guò)了延遲時(shí)間ms,那么就完全看不出來(lái)有時(shí)間間隔了

4、promise和process.nextTick與async/await

事件循環(huán)的順序,決定js代碼的執(zhí)行順序。進(jìn)入整體代碼(宏任務(wù))后,開(kāi)始第一次循環(huán)。接著執(zhí)行所有的微任務(wù)。然后再次從宏任務(wù)開(kāi)始,找到其中一個(gè)任務(wù)隊(duì)列執(zhí)行完畢,再執(zhí)行所有的微任務(wù)。

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

macro-task(宏任務(wù)):包括整體代碼script、setTimeout、setInterval、I/O、UI交互事件,可以理解是每次執(zhí)行棧執(zhí)行的代碼就是一個(gè)宏任務(wù);

micro-task(微任務(wù)):Promise,process.nextTick,且process.nextTick優(yōu)先級(jí)大于promise.then。可以理解是在當(dāng)前 task 執(zhí)行結(jié)束后立即執(zhí)行的任務(wù);

setTimeout(fn, 0)在下一輪“事件循環(huán)”開(kāi)始時(shí)執(zhí)行,Promise.then()在本輪“事件循環(huán)”結(jié)束時(shí)執(zhí)行。

不同類(lèi)型的任務(wù)會(huì)進(jìn)入對(duì)應(yīng)的Event Queue:

Promise中的異步體現(xiàn)在thencatch中,所以寫(xiě)在Promise中的代碼是被當(dāng)做同步任務(wù)立即執(zhí)行的。

await實(shí)際上是一個(gè)讓出線程的標(biāo)志。await后面的表達(dá)式會(huì)先執(zhí)行一遍,將await后面的代碼加入到microtask中,然后就會(huì)跳出整個(gè)async函數(shù)來(lái)執(zhí)行后面的代碼;

因?yàn)閍sync await 本身就是promise+generator的語(yǔ)法糖。所以await后面的代碼是microtask。

下面開(kāi)始分析開(kāi)頭的代碼

console.log("1");
async function async1() {
    console.log("2");
    await async2();
    console.log("3");
}
async function async2() {
    console.log("4");
}

process.nextTick(function() {
    console.log("5");
})

setTimeout(function() {
    console.log("6");
    process.nextTick(function() {
        console.log("7");
    })
    new Promise(function(resolve) {
        console.log("8");
        resolve();
    }).then(function() {
        console.log("9")
    })
})

async1();

new Promise(function(resolve) {
    console.log("10");
    resolve();
}).then(function() {
    console.log("11");
});
console.log("12");

第一輪事件循環(huán)流程:

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

遇到async1、async2函數(shù)聲明,聲明暫時(shí)不用管

遇到process.nextTick(),其回調(diào)函數(shù)被分發(fā)到微任務(wù)Event Queue中。我們記為process1

遇到setTimeout,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)Event Queue中。我們暫且記為setTimeout1

執(zhí)行async1,遇到console.log,輸出2

下面這里是最難理解的地方

我們知道使用 async 定義的函數(shù),當(dāng)它被調(diào)用時(shí),它返回的是一個(gè)Promise對(duì)象

而當(dāng)await后面的表達(dá)式是一個(gè)Promise時(shí),它的返回值實(shí)際上是Promise的回調(diào)函數(shù)resolve的參數(shù)

遇到await async2()調(diào)用,發(fā)現(xiàn)async2也是一個(gè) async 定義的函數(shù),所有直接執(zhí)行輸出4,同時(shí)返回了一個(gè)Promise。劃重點(diǎn):此時(shí)返回的Promise被分配到微任務(wù)Event Queue中,我們記為await1。await會(huì)讓出線程,接下來(lái)就會(huì)跳出async1函數(shù)繼續(xù)往下執(zhí)行。

遇到Promise,new Promise直接執(zhí)行,輸出10。then被分發(fā)到微任務(wù)Event Queue中。我們記為then1

遇到console.log,輸出12

宏任務(wù)Event Queue 微任務(wù)Event Queue
setTimeout1 process1
await1
then1

上表是第一輪事件循環(huán)宏任務(wù)結(jié)束時(shí)各Event Queue的情況,此時(shí)已經(jīng)輸出了1 2 4 10 12

我們發(fā)現(xiàn)了process1await1 then1三個(gè)微任務(wù)

執(zhí)行process1,輸出5

取到 await1 ,就是 async1 放進(jìn)去的Promise,執(zhí)行Promise時(shí)發(fā)現(xiàn)又遇到了他的真命天子resolve函數(shù),劃重點(diǎn):這個(gè)resolve又會(huì)被放入微任務(wù)Event Queue中,我們記為await2,然后再次跳出 async1函數(shù) 繼續(xù)下一個(gè)任務(wù)。

執(zhí)行then1,輸出11

宏任務(wù)Event Queue 微任務(wù)Event Queue
setTimeout1 await2

到這里,已經(jīng)輸出了1 2 4 10 12 5 11

此時(shí)還有一個(gè)await2 微任務(wù)

它是async1 放進(jìn)去的Promise的resolve回調(diào),執(zhí)行它(因?yàn)?async2 并沒(méi)有return東西,所以這個(gè)resolve的參數(shù)是undefined),此時(shí) await 定義的這個(gè) Promise 已經(jīng)執(zhí)行完并且返回了結(jié)果,所以可以繼續(xù)往下執(zhí)行 async1函數(shù) 后面的任務(wù)了,那就是console.log(3),輸出3

到這里,第一輪事件循環(huán)結(jié)束,此時(shí),輸出順序是 1 2 4 10 12 5 11 3

第二輪時(shí)間循環(huán)從setTimeout1宏任務(wù)開(kāi)始

遇到console.log,輸出6

遇到process.nextTick(),同樣將其分發(fā)到微任務(wù)Event Queue中,記為process2

遇到new Promise立即執(zhí)行輸出8,then也分發(fā)到微任務(wù)Event Queue中,記為then2

宏任務(wù)Event Queue 微任務(wù)Event Queue
process2
then2

上表是第二輪事件循環(huán)宏任務(wù)結(jié)束時(shí)各Event Queue的情況,此時(shí)輸出情況是

我們發(fā)現(xiàn)了process2then2兩個(gè)微任務(wù)

執(zhí)行process2,輸出7

執(zhí)行then2,輸出9

第二輪事件循環(huán)結(jié)束,第二輪輸出6 8 7 9

整段代碼,共進(jìn)行了兩次事件循環(huán),完整的輸出 1 2 4 10 12 5 11 3 6 8 7 9

四、寫(xiě)在最后

到這里,大家應(yīng)該已經(jīng)清楚了JS的事件循環(huán)機(jī)制,后面不管在工作還是面試中,肯定都是游刃有余啦~

本篇是我開(kāi)始的第一篇文章,還希望大家多多支持,不吝賜教哇,也希望可以提出意見(jiàn)或建議。

資料參考:

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

https://juejin.im/post/59e85e...

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

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

相關(guān)文章

  • 筆試題之Event Loop終極

    摘要:下面開(kāi)始分析開(kāi)頭的代碼第一輪事件循環(huán)流程整體作為第一個(gè)宏任務(wù)進(jìn)入主線程,遇到,輸出遇到函數(shù)聲明,聲明暫時(shí)不用管遇到,其回調(diào)函數(shù)被分發(fā)到微任務(wù)中。我們記為遇到,其回調(diào)函數(shù)被分發(fā)到宏任務(wù)中。 先上一道常見(jiàn)的筆試題 console.log(1); async function async1() { console.log(2); await async2(); con...

    niceforbear 評(píng)論0 收藏0
  • 【進(jìn)階4-3期】面試題之如何實(shí)現(xiàn)一個(gè)深拷貝

    摘要:今天這篇文章我們來(lái)看看一道必會(huì)面試題,即如何實(shí)現(xiàn)一個(gè)深拷貝。木易楊注意這里使用上面測(cè)試用例測(cè)試一下一個(gè)簡(jiǎn)單的深拷貝就完成了,但是這個(gè)實(shí)現(xiàn)還存在很多問(wèn)題。 引言 上篇文章詳細(xì)介紹了淺拷貝 Object.assign,并對(duì)其進(jìn)行了模擬實(shí)現(xiàn),在實(shí)現(xiàn)的過(guò)程中,介紹了很多基礎(chǔ)知識(shí)。今天這篇文章我們來(lái)看看一道必會(huì)面試題,即如何實(shí)現(xiàn)一個(gè)深拷貝。本文會(huì)詳細(xì)介紹對(duì)象、數(shù)組、循環(huán)引用、引用丟失、Symbo...

    longmon 評(píng)論0 收藏0
  • 騰訊CDC面試題之五子棋 - dom版(ES6)

    摘要:廢話(huà)不多說(shuō)上代碼完整項(xiàng)目地址項(xiàng)目地址棋盤(pán)樣式棋盤(pán)元素初始化初始化角色黑旗子白旗是否已分出勝負(fù)走棋記錄當(dāng)前步清空棋子和事件初始化棋盤(pán)矩陣刻畫(huà)棋盤(pán)棋盤(pán)網(wǎng)格刻畫(huà)棋子每次落子結(jié)束都要判斷輸贏落子如果點(diǎn)擊的是棋子則中斷空的棋位才可落子落 廢話(huà)不多說(shuō)上代碼!完整項(xiàng)目地址:GitHub項(xiàng)目地址 class Gobang { constructor(options) { ...

    韓冰 評(píng)論0 收藏0
  • 面試題之從敲入 URL 到瀏覽器渲染完成

    摘要:響應(yīng)由三個(gè)部分組成,分別是狀態(tài)行消息報(bào)頭響應(yīng)正文。詳情參考小汪之前寫(xiě)的文章瀏覽器內(nèi)核之解釋器和模型解釋解釋過(guò)程是指從字符串經(jīng)過(guò)解釋器處理后變成渲染引擎內(nèi)部規(guī)則的表示過(guò)程。 showImg(https://segmentfault.com/img/remote/1460000016404846); 前言 小汪最近在看【W(wǎng)ebKit 技術(shù)內(nèi)幕】一書(shū),說(shuō)實(shí)話(huà),這本書(shū)寫(xiě)的太官方了,不通俗易懂。...

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

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

0條評(píng)論

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