成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

瀏覽器和Node中的事件循環(huán)機(jī)制

KevinYan / 2512人閱讀

摘要:二瀏覽器端在講解事件循環(huán)之前先談?wù)勚型酱a異步代碼的執(zhí)行流程。三端我自己認(rèn)為的事件循環(huán)和瀏覽器端還是有點(diǎn)區(qū)別的,它的事件循環(huán)依靠引擎。四總結(jié)本篇主要介紹了瀏覽器和對(duì)于事件循環(huán)機(jī)制實(shí)現(xiàn),由于能力水平有限,其中可能有誤之處歡迎指出。

一、前言

前幾天聽(tīng)公司一個(gè)公司三年的前端說(shuō)“今天又學(xué)到了一個(gè)知識(shí)點(diǎn)-微任務(wù)、宏任務(wù)”,我問(wèn)他這是什么東西,由于在吃飯他淺淺的說(shuō)了下,當(dāng)時(shí)沒(méi)太理解就私下學(xué)習(xí)整理一番,由于談微任務(wù)、宏任務(wù)必談到事件循環(huán),于是就有了這篇博客。

在談到事件循環(huán)機(jī)制之前我們需要知道一些基礎(chǔ)知識(shí)就是:

js是單線(xiàn)程的

js一開(kāi)始是作為腳本語(yǔ)言運(yùn)行在客戶(hù)端

其實(shí)js是單線(xiàn)程在它作為腳本語(yǔ)言操作dom的時(shí)候就決定了。那么此時(shí)就有一個(gè)性能問(wèn)題,那么js在瀏覽器端是如何處理這個(gè)問(wèn)題的呢?同時(shí),js在后臺(tái)Node中又是如何解決的呢?這就是本篇需要介紹的事件循環(huán)機(jī)制,這里我將分別以瀏覽器和Node兩個(gè)方面來(lái)分析。

二、瀏覽器端

在講解事件循環(huán)之前先談?wù)刯s中同步代碼、異步代碼的執(zhí)行流程。

2.1、js同步代碼執(zhí)行過(guò)程

js引擎在執(zhí)行通過(guò)代碼的過(guò)程中,會(huì)安裝順序依次存儲(chǔ)到一個(gè)地方去,這個(gè)地方就叫做執(zhí)行棧,當(dāng)我們調(diào)用一個(gè)方法的時(shí)候,js會(huì)生成一個(gè)和這個(gè)方法相對(duì)應(yīng)的上下文(context)。這個(gè)執(zhí)行環(huán)境中存在著這個(gè)方法的私有作用域,上層作用域的指向,方法的參數(shù),這個(gè)作用域中定義的變量以及這個(gè)作用域的this對(duì)象。

function a() {
    console.log("method a execute...");
}
function b() {
    a();
}
function c() {
    b();
}
c();

以上面例子分析:js在執(zhí)行的時(shí)候會(huì)有一個(gè)全局上下文,我們這里就稱(chēng)為GContext,下面分析步驟

調(diào)用c(),c入棧,此時(shí)棧中內(nèi)容為:GContext->c-contextC

接著調(diào)用b(),b入棧,此時(shí)棧中內(nèi)容為:GContext->c->contextC->b->contextB

接著調(diào)用a(),a入棧,此時(shí)棧中內(nèi)容為:GContext->c->contextC->b->contextB-c->contextC

a執(zhí)行完,a出棧,此時(shí)棧中內(nèi)容為:GContext->c->contextC->b->contextB

b執(zhí)行完,b出棧,此時(shí)棧中內(nèi)容為:GContext->c->contextC

c執(zhí)行完,b出棧,此時(shí)棧中內(nèi)容為:GContext

全部執(zhí)行完,釋放資源

ok,上面是同步代碼的執(zhí)行,上面會(huì)涉及到兩個(gè)核心概念:執(zhí)行整個(gè)代碼的線(xiàn)程我們稱(chēng)之為主線(xiàn)程,存放方法執(zhí)行的地方我們稱(chēng)之為執(zhí)行棧.

2.2、js異步代碼執(zhí)行過(guò)程

上面說(shuō)完了同步過(guò)程,那這里來(lái)談?wù)劗惒降倪^(guò)程。js引擎在遇到一個(gè)異步事件,不會(huì)一直等待返回結(jié)果而是將它掛起。當(dāng)異步任務(wù)執(zhí)行完之后會(huì)將結(jié)果加入到和執(zhí)行棧中不同的任務(wù)隊(duì)列當(dāng)中,注意的是:此時(shí)放入隊(duì)列不會(huì)立即執(zhí)行其回調(diào),而是當(dāng)主線(xiàn)程執(zhí)行完執(zhí)行棧中所有的任務(wù)之后再去隊(duì)列中查找是否有任務(wù),如果有則取出排在第一位的事件然后將回調(diào)放入執(zhí)行棧并執(zhí)行其代碼。如此反復(fù)就構(gòu)成了事件循環(huán)。

這里同樣有一個(gè)核心概念:任務(wù)隊(duì)列

2.3、微任務(wù)、宏任務(wù)

上面提到j(luò)s執(zhí)行異步方法的時(shí)候會(huì)將其返回結(jié)果放到隊(duì)列中,這是比較籠統(tǒng)的,具體來(lái)說(shuō),js會(huì)根據(jù)任務(wù)的類(lèi)型將其放入不同的隊(duì)列,任務(wù)類(lèi)型有兩種:微任務(wù)、宏任務(wù)。那么其對(duì)應(yīng)的哪些是微任務(wù)、哪些是宏任務(wù)呢?

微任務(wù):Promise、process.nextTick()、整體代碼script、Object.observer、MutationObserver

宏任務(wù):setTimeout()、setInterval()

瀏覽器在執(zhí)行的時(shí)候,先從宏任務(wù)隊(duì)列中取出一個(gè)宏任務(wù)執(zhí)行宏,然后在執(zhí)行該宏任務(wù)下的所有的微任務(wù),這是一個(gè)循環(huán);然后再取出并執(zhí)行下一個(gè)宏任務(wù),再執(zhí)行所有的微任務(wù),這是第二個(gè)循環(huán),以此類(lèi)推.

注意:整個(gè)javascript代碼是第一個(gè)宏任務(wù)
const process = require("process")
setTimeout(function () {// 分發(fā)宏任務(wù)到EventQueue
    console.log("1");
}, 0);
setTimeout(() => {
    console.log("11");
}, 0);
setTimeout(() => {
    console.log("111");
}, 0);
new Promise(function (resolve) {
    console.log("2");
    resolve();
}).then(function () {// 發(fā)送微任務(wù)
    console.log("3");
});
// 輸出
2
3
1
11
111
2.4、小結(jié)

在瀏覽器端,在我們執(zhí)行一片script的時(shí)候,當(dāng)遇到同步代碼,依次進(jìn)入執(zhí)行棧,遇到異步代碼,將其掛起,繼續(xù)執(zhí)行其它方法,當(dāng)異步方法執(zhí)行完之后根據(jù)任務(wù)類(lèi)型進(jìn)入到任務(wù)隊(duì)列,在執(zhí)行棧執(zhí)行完,主線(xiàn)程空閑下來(lái)了之后會(huì)到任務(wù)隊(duì)列中取任務(wù)回調(diào)并執(zhí)行。

三、Node端

我自己認(rèn)為Node的事件循環(huán)和瀏覽器端還是有點(diǎn)區(qū)別的,它的事件循環(huán)依靠libuv引擎。

該圖來(lái)自官網(wǎng),這里展示了在node的事件循環(huán)的6個(gè)階段。

timers:該階段執(zhí)行定時(shí)器的回調(diào),如setTimeout() 和 setInterval()。

I/O callbacks:該階段執(zhí)行除了close事件,定時(shí)器和setImmediate()的回調(diào)外的所有回調(diào)

idle, prepare:內(nèi)部使用

poll:等待新的I/O事件,node在一些特殊情況下會(huì)阻塞在這里

check: setImmediate()的回調(diào)會(huì)在這個(gè)階段執(zhí)行

close callbacks: 例如socket.on("close", ...)這種close事件的回調(diào)

對(duì)于我們來(lái)說(shuō)我們更關(guān)注 timer、poll、check這三個(gè)階段即可。

poll 階段有兩個(gè)主要的功能:

處理poll隊(duì)列(poll quenue)的事件(callback);

執(zhí)行timers的callback,當(dāng)?shù)竭_(dá)timers指定的時(shí)間時(shí);

poll 階段的邏輯

如果event loop進(jìn)入了 poll階段,且代碼未設(shè)定timer,將會(huì)發(fā)生下面情況:

a、如果poll queue不為空,event loop將同步的執(zhí)行queue里的callback,直至queue為空,或執(zhí)行的callback到達(dá)系統(tǒng)上限;

b、如果poll queue為空,將會(huì)發(fā)生下面情況:

* 如果代碼已經(jīng)被setImmediate()設(shè)定了callback, event loop將結(jié)束poll階段進(jìn)入check階段,并執(zhí)行check階段的queue (check階段的queue是 setImmediate設(shè)定的)
* 如果代碼沒(méi)有設(shè)定setImmediate(callback),event loop將阻塞在該階段等待callbacks加入poll queue;

如果event loop進(jìn)入了 poll階段,且代碼設(shè)定了timer:

如果poll queue進(jìn)入空狀態(tài)時(shí)(即poll 階段為空閑狀態(tài)),event loop將檢查timers,

如果有1個(gè)或多個(gè)timers時(shí)間時(shí)間已經(jīng)到達(dá),event loop將按循環(huán)順序進(jìn)入 timers 階段,并執(zhí)行timer queue

3.1、setTimeout、setImmediate

這兩個(gè)函數(shù)的功能還是類(lèi)似的,不同的是他們處于EventLoop的不同階段:timer、check。

setImmediate(()=>console.log("setInterval"));
setTimeout(() => {console.log("setTimeout")},0);

上面兩行代碼會(huì)輸出順序是什么呢?其實(shí)兩種可能都有.
1.當(dāng)setTimeout的0ms并不能做到絕對(duì)0ms,如果已經(jīng)過(guò)了timer階段,那么此時(shí)setTimeout就會(huì)在下一次循環(huán)中執(zhí)行,也就是說(shuō)先setInterval、再setTimeout。
2.第二種可能就是正常流程了,先timer、再check

如果上面的代碼再一個(gè)IO操作作呢?如:

require("fs").readFile(__filename,()=>{
    setImmediate(()=>console.log("setInterval"));
    setTimeout(() => {console.log("setTimeout")});
})

此時(shí)只可能出現(xiàn)一種情況,先setInterval、再setTimeout,因?yàn)樵趇o中已經(jīng)執(zhí)行過(guò)了timer(readFile時(shí)處于IO callback)。
下面一起來(lái)看如下代碼:

setTimeout(() => {
    console.log("timer1")
    Promise.resolve().then(() => console.log("promise1"));
    process.nextTick(() => console.log("nextTick1"))
}, 0);
setTimeout(() => {
    console.log("timer2")
    Promise.resolve().then(() => console.log("promise2"));
    process.nextTick(() => console.log("nextTick2"))
}, 0);

按照我的理解,它的輸出應(yīng)該是如下:先timer、然后切換階段的時(shí)候執(zhí)行微任務(wù).

// 情況1
timer1
timer2
nextTick1
nextTick2
promise1
promise2

可是并不是,它的輸出一直是:

// 情況2
timer1
nextTick1
promise1
timer2
nextTick2
promise2

后臺(tái)晚上查資料因?yàn)镹ode11對(duì)EventLoop作了修改,為了和瀏覽器兼容。于是呼我切換到10.8.0,發(fā)現(xiàn)上面兩種情況都有(情況1比例大于情況2)。這點(diǎn)暫時(shí)還未查明什么原因。

3.2、小結(jié)

node中的6個(gè)階段每個(gè)階段執(zhí)行完都會(huì)伴隨著執(zhí)行微任務(wù),同個(gè)MicroTask隊(duì)列下process.tick()會(huì)優(yōu)于Promise。

四 總結(jié)

本篇主要介紹了瀏覽器和Node對(duì)于事件循環(huán)機(jī)制實(shí)現(xiàn),由于能力水平有限,其中可能有誤之處歡迎指出。

歡迎關(guān)注公眾號(hào):

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

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

相關(guān)文章

  • JS與Node.js中的事件循環(huán)

    摘要:的單線(xiàn)程,與它的用途有關(guān)。特點(diǎn)的顯著特點(diǎn)異步機(jī)制事件驅(qū)動(dòng)。隊(duì)列的讀取輪詢(xún)線(xiàn)程,事件的消費(fèi)者,的主角。它將不同的任務(wù)分配給不同的線(xiàn)程,形成一個(gè)事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 這兩天跟同事同事討論遇到的一個(gè)問(wèn)題,js中的event loop,引出了chrome與node中運(yùn)行具有setTimeout和Promise的程序時(shí)候執(zhí)行結(jié)果不一樣的問(wèn)題,從而引出了Nodejs的...

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

    摘要:?jiǎn)尉€(xiàn)程的話(huà),如果我們做一些的操作比如說(shuō)這是一個(gè)耗時(shí)的操所那么在這將近一秒內(nèi),線(xiàn)程就會(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事件機(jī)制的實(shí)現(xiàn)(一)—— Node.js事件驅(qū)動(dòng)實(shí)現(xiàn)概覽

    摘要:如果當(dāng)前沒(méi)有事件也沒(méi)有定時(shí)器事件,則返回。相關(guān)資料關(guān)于的架構(gòu)及設(shè)計(jì)思路的事件討論了使用線(xiàn)程池異步運(yùn)行代碼。下一篇初窺事件機(jī)制的實(shí)現(xiàn)二中定時(shí)器的實(shí)現(xiàn) 在瀏覽器中,事件作為一個(gè)極為重要的機(jī)制,給予JavaScript響應(yīng)用戶(hù)操作與DOM變化的能力;在Node.js中,事件驅(qū)動(dòng)模型則是其高并發(fā)能力的基礎(chǔ)。 學(xué)習(xí)JavaScript也需要了解它的運(yùn)行平臺(tái),為了更好的理解JavaScript的事...

    lavor 評(píng)論0 收藏0
  • Node中的事件循環(huán)

    摘要:的事件循環(huán)一個(gè)線(xiàn)程有唯一的一個(gè)事件循環(huán)。索引就是指否還有需要執(zhí)行的事件,是否還有請(qǐng)求,關(guān)閉事件循環(huán)的請(qǐng)求等等。先來(lái)看一下定義的定義是在事件循環(huán)的下一個(gè)階段之前執(zhí)行對(duì)應(yīng)的回調(diào)。雖然是這樣定義的,但是它并不是為了在事件循環(huán)的每個(gè)階段去執(zhí)行的。 Node中的事件循環(huán) 如果對(duì)前端瀏覽器的時(shí)間循環(huán)不太清楚,請(qǐng)看這篇文章。那么node中的事件循環(huán)是什么樣子呢?其實(shí)官方文檔有很清楚的解釋?zhuān)疚南葟膎...

    lwx12525 評(píng)論0 收藏0
  • 覽器Node不同的事件循環(huán)(Event Loop)

    摘要:瀏覽器中與中事件循環(huán)與執(zhí)行機(jī)制不同,不可混為一談。瀏覽器環(huán)境執(zhí)行為單線(xiàn)程不考慮,所有代碼皆在執(zhí)行線(xiàn)程調(diào)用棧完成執(zhí)行。參考文章強(qiáng)烈推薦不要混淆和瀏覽器中的強(qiáng)烈推薦中的模塊強(qiáng)烈推薦理解事件循環(huán)一淺析定時(shí)器詳解 注意 在 node 11 版本中,node 下 Event Loop 已經(jīng)與瀏覽器趨于相同。在 node 11 版本中,node 下 Event Loop 已經(jīng)與瀏覽器趨于相同。在 ...

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

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

0條評(píng)論

閱讀需要支付1元查看
<