溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Javascript的Event?Loop怎么實(shí)現(xiàn)

發(fā)布時(shí)間:2021-12-30 13:35:01 來(lái)源:億速云 閱讀:154 作者:iii 欄目:開(kāi)發(fā)技術(shù)

本篇內(nèi)容主要講解“Javascript的Event Loop怎么實(shí)現(xiàn)”,感興趣的朋友不妨來(lái)看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來(lái)帶大家學(xué)習(xí)“Javascript的Event Loop怎么實(shí)現(xiàn)”吧!

一、四個(gè)概念

1、Javascript是單線程

單線程意味著我們的js代碼只能從上往下同步執(zhí)行,同一時(shí)間只能執(zhí)行一個(gè)任務(wù),這會(huì)導(dǎo)致某些執(zhí)行時(shí)間較長(zhǎng)或者執(zhí)行時(shí)間不確定的任務(wù)會(huì)卡住其它任務(wù)的正常執(zhí)行,Event Loop出現(xiàn)的原因正是為了解決此問(wèn)題。

2、任務(wù)隊(duì)列

為了解決上述的排隊(duì)問(wèn)題,有了任務(wù)隊(duì)列,瀏覽器在異步任務(wù)有了結(jié)果后,將其添加到任務(wù)隊(duì)列,以待將來(lái)執(zhí)行,其他任務(wù)就在主線程上同步執(zhí)行。

這里要注意的是,向任務(wù)隊(duì)列中添加任務(wù)的時(shí)機(jī)是異步任務(wù)有結(jié)果后。其實(shí)任務(wù)隊(duì)列中存在的就是異步任務(wù)的回調(diào)函數(shù)。

3、同步任務(wù)、異步任務(wù)

Js程序中的同步任務(wù)是指在主線程中執(zhí)行的任務(wù),異步任務(wù)是指進(jìn)入任務(wù)隊(duì)列中的任務(wù)

4、Javascript執(zhí)行棧

所有的同步任務(wù)都在主線程上執(zhí)行,行成一個(gè)執(zhí)行棧。當(dāng)主線程上任務(wù)執(zhí)行完畢后,從任務(wù)隊(duì)列中取出任務(wù)執(zhí)行。

var name = "zhouwei";

setTimeout(() => {
    console.log(1);
}, 1000);

console.log(name);

上面代碼在瀏覽器中執(zhí)行如下,我們將程序全局執(zhí)行環(huán)境的代碼理解為包裹在一個(gè)main函數(shù)中的代碼,這段代碼的執(zhí)行棧變化如下圖:

Javascript的Event?Loop怎么實(shí)現(xiàn)

  • 開(kāi)始執(zhí)行代碼,將main任務(wù)(全局代碼入棧執(zhí)行),當(dāng)遇到異步任務(wù)(setTimeout后)。

  • 瀏覽器接管異步任務(wù),并在1s后將異步任務(wù)的結(jié)果(回調(diào)函數(shù))添加到任務(wù)隊(duì)列。

  • 執(zhí)行棧中的同步任務(wù)執(zhí)行完畢,此時(shí)任務(wù)隊(duì)列為空(未到1s),執(zhí)行棧也為空

  • 異步任務(wù)有結(jié)果后,首先進(jìn)入任務(wù)隊(duì)列排隊(duì)(因?yàn)榭赡苡泻芏喈惒饺蝿?wù))。

  • 執(zhí)行棧從任務(wù)隊(duì)列中取出任務(wù)開(kāi)始同步執(zhí)行。

  • 重復(fù)執(zhí)行第5步。

二、Event Loop

Js執(zhí)行棧不斷的從任務(wù)隊(duì)列中讀取任務(wù)并執(zhí)行的過(guò)程就是Event Loop

我們知道任務(wù)隊(duì)列中存放的是異步任務(wù)的結(jié)果,那么異步任務(wù)都有哪些了?

  • 1、事件

Javascript中的事件有很多,都是屬于異步任務(wù)。由瀏覽器接管,當(dāng)事件觸發(fā)時(shí),將事件的回調(diào)加入的任務(wù)隊(duì)列中,在Js執(zhí)行棧中沒(méi)有任務(wù)時(shí)執(zhí)行。

  • 2、Http請(qǐng)求

  • 3、定時(shí)器

  • 4、requestAnimationFrame等

宏任務(wù)(macrotask)和微任務(wù)(microtask)
在了解了任務(wù)隊(duì)列和Event Loop后,我們知道了Js執(zhí)行棧從任務(wù)隊(duì)列中讀取任務(wù)執(zhí)行,但這個(gè)具體工程我們?nèi)蝿?wù)不清楚,這里引出了宏任務(wù)和微任務(wù)的的概念,幫助我們理解Event Loop。

進(jìn)入任務(wù)隊(duì)列中的異步任務(wù)回調(diào)分為了宏任務(wù)和微任務(wù), Js執(zhí)行棧執(zhí)行宏任務(wù)和微任務(wù)的規(guī)則如下圖所示。

Javascript的Event?Loop怎么實(shí)現(xiàn)

Js執(zhí)行棧首先執(zhí)行一個(gè)宏任務(wù)(全局代碼) -> 從任務(wù)隊(duì)列中讀取所有微任務(wù)執(zhí)行 -> UI rendering(瀏覽器渲染界面) -> 從任務(wù)隊(duì)列讀取一個(gè)宏任務(wù) -> 所有微任務(wù) -> UI rendering -> …

在每一輪的Event Loop結(jié)束后(1個(gè)宏任務(wù) + 所有微任務(wù)),瀏覽器開(kāi)始渲染界面(如果有需要渲染的UI,否則不執(zhí)行UI rendering),在UI rendering結(jié)束后,開(kāi)始下一輪Event Loop。

哪些是宏任務(wù)?

  • setTimeout

  • setInterval

  • setImmediate (Node)

  • requestAnimationFrame (瀏覽器)

  • I/O (事件回調(diào))

  • UI rendering (瀏覽器渲染)

哪些是微任務(wù)?

  • Promise

  • process.nextTick (Node)

  • MutationObserver (現(xiàn)代瀏覽器提供的用來(lái)檢測(cè) DOM 變化的網(wǎng)頁(yè)接口)

setTimeout延時(shí)問(wèn)題

一般來(lái)說(shuō)在代碼中setTimeout中回調(diào)的執(zhí)行時(shí)間都是大于設(shè)置的時(shí)間。 這是因?yàn)樵?code>setTimeout指定時(shí)間到達(dá)后,雖然回調(diào)函數(shù)被添加到了任務(wù)隊(duì)列,但是此時(shí)Js執(zhí)行棧中可能有正在執(zhí)行的任務(wù),此回調(diào)需要等待Js執(zhí)行棧的任務(wù)執(zhí)行完畢后才有機(jī)會(huì)執(zhí)行,這就是setTimeout延時(shí)問(wèn)題。

三、實(shí)戰(zhàn)

練習(xí)下下方代碼輸出結(jié)果吧:

console.log(1);

setTimeout(() => {
    console.log(2);
    Promise.resolve().then(() => {
        console.log(3)
    });
});

new Promise(resolve => {
    console.log(4);
    setTimeout(() => {
        console.log(5);
    });
    resolve(6)
}).then(data => {
    console.log(data);
})

setTimeout(() => {
    console.log(7);
})

console.log(8);

用上方的我們說(shuō)過(guò)的js執(zhí)行機(jī)制來(lái)分析這道題:

1: 執(zhí)行全局任務(wù)中的同步代碼輸出:

1
4
8

這里需要注意的是Promise接受的handle函數(shù)是同步任務(wù),而then方法是異步任務(wù),所以會(huì)直接輸出4。

2: 這時(shí)的任務(wù)隊(duì)列中有三個(gè)setTimeout的宏任務(wù),和一個(gè)Promise的微任務(wù)

// 此時(shí)的宏任務(wù)是

setTimeout(() => {
    console.log(2);
    Promise.resolve().then(() => {
        console.log(3)
    });
});

setTimeout(() => {
    console.log(5);
});


setTimeout(() => {
    console.log(7);
})

// 此時(shí)微任務(wù)是
then(data => {
    console.log(data);
})

執(zhí)行一個(gè)微任務(wù), 輸出:6

3: 接著執(zhí)行第一個(gè)宏任務(wù)

setTimeout(() => {
    console.log(2);
    Promise.resolve().then(() => {
        console.log(3)
    });
});

輸出:2

在此宏任務(wù)中,向任務(wù) 隊(duì)列添加了一個(gè)微任務(wù)。此時(shí)任務(wù)隊(duì)列有了新的微任務(wù)。

4:執(zhí)行一個(gè)微任務(wù),輸出:3

then(() => {
   console.log(3)
});

5: 繼續(xù)按照規(guī)則執(zhí)行任務(wù), 輸出: 5、7

整體輸出情況是:

1、4、8、6、2、3、5、7

到此,相信大家對(duì)“Javascript的Event Loop怎么實(shí)現(xiàn)”有了更深的了解,不妨來(lái)實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI