亚洲直播在线一区_国产免费一区二区三区_在线观看h片_日韩三级在线免费观看_亚洲精品乱码日韩_自拍视频在线看_国产精品剧情在线亚洲_精品一区二区三区国产_丝袜美腿诱惑一区二区三区_欧美区一区二区三区_www.av99_亚洲国产日韩欧美在线

你好,游客 登錄 注冊(cè) 搜索
背景:
閱讀新聞

詳解JavaScript運(yùn)行機(jī)制(Event Loop)

[日期:2019-10-11] 來(lái)源: 51CTO  作者:浪里行舟 [字體: ]

 

前言

在瀏覽器中,每個(gè)渲染進(jìn)程都有一個(gè)主線程,主線程非常繁忙,既要處理DOM,又要計(jì)算樣式,還要處理布局,同時(shí)還需要處理JavaScript任務(wù)以及各種輸入事件。此時(shí)我們就需要一個(gè)系統(tǒng)來(lái)統(tǒng)籌調(diào)度這么多不同類型的任務(wù)在主線程中有條不紊地執(zhí)行,而這個(gè)統(tǒng)籌調(diào)度系統(tǒng)就是本文要介紹的事件循環(huán)系統(tǒng)(Event Loop)。

讀完本文,希望你能明白:

  • 進(jìn)程與線程的區(qū)別
  • 最新的Chrome瀏覽器包括哪些進(jìn)程?
  • 瀏覽器與Node的事件循環(huán)(Event Loop)有何區(qū)別?

一、進(jìn)程與線程

1.概念

我們經(jīng)常說(shuō)JavaScript是單線程執(zhí)行的,那到底什么是線程?什么是進(jìn)程?

一個(gè)進(jìn)程就是一個(gè)程序的運(yùn)行實(shí)例。詳細(xì)解釋就是,啟動(dòng)一個(gè)程序的時(shí)候,操作系統(tǒng)會(huì)為該程序創(chuàng)建一塊內(nèi)存,用來(lái)存放代碼、運(yùn)行中的數(shù)據(jù)和一個(gè)執(zhí)行任務(wù)的主線程,我們把這樣的一個(gè)運(yùn)行環(huán)境叫進(jìn)程。

而線程是操作系統(tǒng)能夠進(jìn)行運(yùn)算調(diào)度的最小單位。線程是不能單獨(dú)存在的,它是由進(jìn)程來(lái)啟動(dòng)和管理的,在進(jìn)程中使用多線程并行處理能提升運(yùn)算效率。

我們通過(guò)以下這張圖來(lái)加深對(duì)兩者的理解:

 

 

 

  • 進(jìn)程好比圖中的工廠,有單獨(dú)的專屬自己的工廠資源。當(dāng)一個(gè)進(jìn)程關(guān)閉之后,操作系統(tǒng)會(huì)回收進(jìn)程所占用的內(nèi)存。
  • 線程好比圖中的工人,多個(gè)工人在一個(gè)工廠中協(xié)作工作,工廠與工人是 1:n的關(guān)系。這意味著一個(gè)進(jìn)程由一個(gè)或多個(gè)線程組成,進(jìn)程中的任意一線程執(zhí)行出錯(cuò),都會(huì)導(dǎo)致整個(gè)進(jìn)程的崩潰。
  • 工廠的空間是工人們共享的,這意味著一個(gè)進(jìn)程的內(nèi)存空間是共享的,每個(gè)線程都可用這些共享內(nèi)存。
  • 多個(gè)工廠之間獨(dú)立存在。這意味著進(jìn)程之間的內(nèi)容相互隔離。

2.多進(jìn)程與多線程

  • 多進(jìn)程:在同一個(gè)時(shí)間里,同一個(gè)計(jì)算機(jī)系統(tǒng)中允許兩個(gè)或兩個(gè)以上的進(jìn)程處于運(yùn)行狀態(tài)。

以最新的 Chrome 瀏覽器為例,我打開掘金編輯文章頁(yè)面時(shí),出現(xiàn)以下五個(gè)進(jìn)程:1個(gè)網(wǎng)絡(luò)進(jìn)程、1個(gè)瀏覽器進(jìn)程、1個(gè)GPU進(jìn)程以及1個(gè)渲染進(jìn)程,共4個(gè);如果打開的頁(yè)面有運(yùn)行插件的話,還需要再加上1個(gè)插件進(jìn)程(下圖有番茄鬧鐘插件)。

 

 

 

  • 多線程:程序中包含多個(gè)執(zhí)行流,即在一個(gè)程序中可以同時(shí)運(yùn)行多個(gè)不同的線程來(lái)執(zhí)行不同的任務(wù),也就是說(shuō)允許單個(gè)程序創(chuàng)建多個(gè)并行執(zhí)行的線程來(lái)完成各自的任務(wù)。

二、最新的 Chrome 進(jìn)程架構(gòu)

最新的Chrome瀏覽器包括:1個(gè)瀏覽器(Browser)主進(jìn)程、1個(gè)GPU進(jìn)程、1個(gè)網(wǎng)絡(luò)(NetWork)進(jìn)程、多個(gè)渲染進(jìn)程和多個(gè)插件進(jìn)程。

 

 

 

接下來(lái)我們介紹下這些進(jìn)程的功能:

  • 瀏覽器進(jìn)程。主要負(fù)責(zé)界面顯示、用戶交互、子進(jìn)程管理,同時(shí)提供存儲(chǔ)等功能。
  • 渲染進(jìn)程。核心任務(wù)是將HTML、CSS 和JavaScript轉(zhuǎn)換為用戶可以與之交互的網(wǎng)頁(yè),排版引擎Blink和JavaScript引擎V8都是運(yùn)行在該進(jìn)程中,默認(rèn)情況下,Chrome 會(huì)為每個(gè)Tab標(biāo)簽創(chuàng)建一個(gè)渲染進(jìn)程。出于安全考慮,渲染進(jìn)程都是運(yùn)行在沙箱模式下。渲染進(jìn)程中主要包含以下線程:主線程(Main thread)、工作線程(Worker thread)、 排版線程 (Compositor thread)和光柵線程(Raster thread)。

 

 

 

  • GPU進(jìn)程。其實(shí),Chrome剛開始發(fā)布的時(shí)候是沒(méi)有GPU進(jìn)程的。而GPU的使用初衷是為了實(shí)現(xiàn)3D CSS的效果,只是隨后網(wǎng)頁(yè)、Chrome 的UI界面都選擇采用GPU來(lái)繪制,這使得GPU成為瀏覽器普遍的需求。最后,Chrome在其多進(jìn)程架構(gòu)上也引入了GPU進(jìn)程。
  • 網(wǎng)絡(luò)進(jìn)程。主要負(fù)責(zé)頁(yè)面的網(wǎng)絡(luò)資源加載,之前是作為一個(gè)模塊運(yùn)行在瀏覽器進(jìn)程里面的,直至最近才獨(dú)立出來(lái),成為一個(gè)單獨(dú)的進(jìn)程。
  • 插件進(jìn)程。主要是負(fù)責(zé)插件的運(yùn)行,因插件易崩潰,所以需要通過(guò)插件進(jìn)程來(lái)隔離,以保證插件進(jìn)程崩潰不會(huì)對(duì)瀏覽器和頁(yè)面造成影響。

頁(yè)面中的大部分任務(wù)都是在渲染進(jìn)程的主線程上執(zhí)行,這些任務(wù)包括了:

  • 渲染事件(如解析 DOM、計(jì)算布局、繪制);
  • 用戶交互事件(如鼠標(biāo)點(diǎn)擊、滾動(dòng)頁(yè)面、放大縮小等);
  • JavaScript腳本執(zhí)行事件;
  • 網(wǎng)絡(luò)請(qǐng)求完成、文件讀寫完成事件。

那么,如何協(xié)調(diào)這些任務(wù)有條不紊地在主線程上執(zhí)行呢? 這就需要事件循環(huán)系統(tǒng)(Event Loop)

三、瀏覽器中的 Event Loop

1.什么是Event Loop

通過(guò)使用消息隊(duì)列,我們實(shí)現(xiàn)了線程之間的消息通信。在Chrome中,跨進(jìn)程之間的任務(wù)也是頻繁發(fā)生的,那么如何處理其他進(jìn)程發(fā)送過(guò)來(lái)的任務(wù)?可以參考下圖(來(lái)源極客時(shí)間):

 

 

 

消息隊(duì)列是一種數(shù)據(jù)結(jié)構(gòu),可以存放要執(zhí)行的任務(wù)。它符合隊(duì)列“先進(jìn)先出”的特點(diǎn),也就是說(shuō)要添加任務(wù)的話,添加到隊(duì)列的尾部;要取出任務(wù)的話,從隊(duì)列頭部去取。

從圖中可以看出,渲染進(jìn)程專門有一個(gè)IO線程用來(lái)接收其他進(jìn)程傳進(jìn)來(lái)的消息,接收到消息之后,會(huì)將這些消息組裝成任務(wù)發(fā)送給渲染主線程。主線程從"消息隊(duì)列"中讀取事件,這個(gè)過(guò)程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))。

2.同步任務(wù)和異步任務(wù)

  • 同步任務(wù)即可以立即執(zhí)行的任務(wù),例如聲明一個(gè)變量或者執(zhí)行一次加法操作等。同步任務(wù)屬于宏任務(wù)。
  • 異步任務(wù)是不會(huì)立即執(zhí)行的事件任務(wù)。異步任務(wù)包括宏任務(wù)和微任務(wù)。

 

 

 

瀏覽器端常見的宏任務(wù)包括:setTimeout、setInterval、script(整體代碼)、 I/O 操作、UI 渲染等;

瀏覽器端常見的微任務(wù)包括:new Promise().then(回調(diào))、MutationObserver(html5新特性) 等。

3.Event Loop 過(guò)程解析

一個(gè)完整瀏覽器端的 Event Loop 過(guò)程,可以概括為以下階段:

 

 

 

  • 一開始執(zhí)行棧空,我們可以把執(zhí)行棧認(rèn)為是一個(gè)存儲(chǔ)函數(shù)調(diào)用的棧結(jié)構(gòu),遵循先進(jìn)后出的原則。微任務(wù)隊(duì)列空,宏任務(wù)隊(duì)列里有且只有一個(gè) script 腳本(整體代碼)。
  • 全局上下文(script 標(biāo)簽)被推入執(zhí)行棧,同步代碼執(zhí)行。在執(zhí)行的過(guò)程中,會(huì)先判斷是同步任務(wù)還是異步任務(wù),也會(huì)產(chǎn)生新的 macro-task 與 micro-task,它們會(huì)分別被推入各自的任務(wù)隊(duì)列里。同步代碼執(zhí)行完了,script 腳本會(huì)被移出 macro 隊(duì)列,這個(gè)過(guò)程本質(zhì)上是隊(duì)列的 macro-task 的執(zhí)行和出隊(duì)的過(guò)程。
  • 上一步我們出隊(duì)的是一個(gè) macro-task,這一步我們處理的是 micro-task。但需要注意的是:當(dāng) macro-task 出隊(duì)時(shí),任務(wù)是一個(gè)一個(gè)執(zhí)行的;而 micro-task 出隊(duì)時(shí),任務(wù)是一隊(duì)一隊(duì)執(zhí)行的。因此,我們處理 micro 隊(duì)列這一步,會(huì)逐個(gè)執(zhí)行隊(duì)列中的任務(wù)并把它出隊(duì),直到隊(duì)列被清空。宏任務(wù)隊(duì)列可以有多個(gè),微任務(wù)隊(duì)列只有一個(gè)。
  • 執(zhí)行渲染操作,更新界面
  • 檢查是否存在 Web worker 任務(wù),如果有,則對(duì)其進(jìn)行處理
  • 上述過(guò)程循環(huán)往復(fù),直到兩個(gè)隊(duì)列都清空

我們總結(jié)一下,每一次循環(huán)都是一個(gè)這樣的過(guò)程:

 

 

 

當(dāng)某個(gè)宏任務(wù)執(zhí)行完后,會(huì)查看是否有微任務(wù)隊(duì)列。如果有,先執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù),如果沒(méi)有,會(huì)讀取宏任務(wù)隊(duì)列中排在最前的任務(wù),執(zhí)行宏任務(wù)的過(guò)程中,遇到微任務(wù),依次加入微任務(wù)隊(duì)列。棧空后,再次讀取微任務(wù)隊(duì)列里的任務(wù),依次類推。

接下來(lái)我們看道例子來(lái)介紹上面流程:

Promise.resolve().then(()=>{ 
console.log('Promise1') 
setTimeout(()=>{ 
 console.log('setTimeout2') 
},0) 
}) 
setTimeout(()=>{ 
console.log('setTimeout1') 
Promise.resolve().then(()=>{ 
 console.log('Promise2') 
}) 
},0) 

最后輸出結(jié)果是Promise1,setTimeout1,Promise2,setTimeout2

  • 一開始執(zhí)行棧的同步任務(wù)(這屬于宏任務(wù))執(zhí)行完畢,會(huì)去查看是否有微任務(wù)隊(duì)列,上題中存在(有且只有一個(gè)),然后執(zhí)行微任務(wù)隊(duì)列中的所有任務(wù)輸出Promise1,同時(shí)會(huì)生成一個(gè)宏任務(wù) setTimeout2
  • 然后去查看宏任務(wù)隊(duì)列,宏任務(wù) setTimeout1 在 setTimeout2 之前,先執(zhí)行宏任務(wù) setTimeout1,輸出 setTimeout1
  • 在執(zhí)行宏任務(wù)setTimeout1時(shí)會(huì)生成微任務(wù)Promise2 ,放入微任務(wù)隊(duì)列中,接著先去清空微任務(wù)隊(duì)列中的所有任務(wù),輸出 Promise2
  • 清空完微任務(wù)隊(duì)列中的所有任務(wù)后,就又會(huì)去宏任務(wù)隊(duì)列取一個(gè),這回執(zhí)行的是 setTimeout2

四、Node 中的 Event Loop

1.Node簡(jiǎn)介

Node 環(huán)境下的 Event Loop 與瀏覽器環(huán)境下的 Event Loop并不相同。Node.js 采用 V8 作為js的解析引擎,而I/O處理方面使用了自己設(shè)計(jì)的libuv,libuv是一個(gè)基于事件驅(qū)動(dòng)的跨平臺(tái)抽象層,封裝了不同操作系統(tǒng)一些底層特性,對(duì)外提供統(tǒng)一的API,事件循環(huán)機(jī)制也是它里面的實(shí)現(xiàn)(下文會(huì)詳細(xì)介紹)。注:本文中所介紹Node 環(huán)境中的 Event Loop,是基于node10及其之前版本。

 

 

 

Node.js的運(yùn)行機(jī)制如下:

  • V8引擎解析JavaScript腳本。
  • 解析后的代碼,調(diào)用Node API。
  • libuv庫(kù)負(fù)責(zé)Node API的執(zhí)行。它將不同的任務(wù)分配給不同的線程,形成一個(gè)Event Loop(事件循環(huán)),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給V8引擎。
  • V8引擎再將結(jié)果返回給用戶。

2.六個(gè)階段

其中l(wèi)ibuv引擎中的事件循環(huán)分為 6 個(gè)階段,它們會(huì)按照順序反復(fù)運(yùn)行。每當(dāng)進(jìn)入某一個(gè)階段的時(shí)候,都會(huì)從對(duì)應(yīng)的回調(diào)隊(duì)列中取出函數(shù)去執(zhí)行。當(dāng)隊(duì)列為空或者執(zhí)行的回調(diào)函數(shù)數(shù)量到達(dá)系統(tǒng)設(shè)定的閾值,就會(huì)進(jìn)入下一階段。

 

 

 

從上圖中,大致看出node中的事件循環(huán)的順序:

外部輸入數(shù)據(jù)-->輪詢階段(poll)-->檢查階段(check)-->關(guān)閉事件回調(diào)階段(close callback)-->定時(shí)器檢測(cè)階段(timer)-->I/O事件回調(diào)階段(I/O callbacks)-->閑置階段(idle, prepare)-->輪詢階段(按照該順序反復(fù)運(yùn)行)...

  • timers 階段:這個(gè)階段執(zhí)行timer(setTimeout、setInterval)的回調(diào)
  • I/O callbacks 階段:處理一些上一輪循環(huán)中的少數(shù)未執(zhí)行的 I/O 回調(diào)
  • idle, prepare 階段:僅node內(nèi)部使用
  • poll 階段:獲取新的I/O事件, 適當(dāng)?shù)臈l件下node將阻塞在這里
  • check 階段:執(zhí)行 setImmediate() 的回調(diào)
  • close callbacks 階段:執(zhí)行 socket 的 close 事件回調(diào)

注意:上面六個(gè)階段都不包括 process.nextTick()(下文會(huì)介紹)

接下去我們?cè)敿?xì)介紹timers、poll、check這3個(gè)階段,因?yàn)槿粘i_發(fā)中的絕大部分異步任務(wù)都是在這3個(gè)階段處理的。

(1) timer

timers 階段會(huì)執(zhí)行 setTimeout 和 setInterval 回調(diào),并且是由 poll 階段控制的。 同樣,在 Node 中定時(shí)器指定的時(shí)間也不是準(zhǔn)確時(shí)間,只能是盡快執(zhí)行。

(2) poll

poll 是一個(gè)至關(guān)重要的階段,這一階段中,系統(tǒng)會(huì)做兩件事情:

1.回到 timer 階段執(zhí)行回調(diào)

2.執(zhí)行 I/O 回調(diào)

并且在進(jìn)入該階段時(shí)如果沒(méi)有設(shè)定了 timer 的話,會(huì)發(fā)生以下兩件事情:

  • 如果 poll 隊(duì)列不為空,會(huì)遍歷回調(diào)隊(duì)列并同步執(zhí)行,直到隊(duì)列為空或者達(dá)到系統(tǒng)限制
  • 如果 poll 隊(duì)列為空時(shí),會(huì)有兩件事發(fā)生
  • 如果有 setImmediate 回調(diào)需要執(zhí)行,poll 階段會(huì)停止并且進(jìn)入到 check 階段執(zhí)行回調(diào)
  • 如果沒(méi)有 setImmediate 回調(diào)需要執(zhí)行,會(huì)等待回調(diào)被加入到隊(duì)列中并立即執(zhí)行回調(diào),這里同樣會(huì)有個(gè)超時(shí)時(shí)間設(shè)置防止一直等待下去

當(dāng)然設(shè)定了 timer 的話且 poll 隊(duì)列為空,則會(huì)判斷是否有 timer 超時(shí),如果有的話會(huì)回到 timer 階段執(zhí)行回調(diào)。

(3) check階段

setImmediate()的回調(diào)會(huì)被加入check隊(duì)列中,從event loop的階段圖可以知道,check階段的執(zhí)行順序在poll階段之后。 我們先來(lái)看個(gè)例子:

console.log('start') 
setTimeout(() => { 
console.log('timer1') 
Promise.resolve().then(function() { 
 console.log('promise1') 
}) 
}, 0) 
setTimeout(() => { 
console.log('timer2') 
Promise.resolve().then(function() { 
 console.log('promise2') 
}) 
}, 0) 
Promise.resolve().then(function() { 
console.log('promise3') 
}) 
console.log('end') 
//start=>end=>promise3=>timer1=>timer2=>promise1=>promise2 
  • 一開始執(zhí)行棧的同步任務(wù)(這屬于宏任務(wù))執(zhí)行完畢后(依次打印出start end,并將2個(gè)timer依次放入timer隊(duì)列),會(huì)先去執(zhí)行微任務(wù)(這點(diǎn)跟瀏覽器端的一樣),所以打印出promise3
  • 然后進(jìn)入timers階段,執(zhí)行timer1的回調(diào)函數(shù),打印timer1,并將promise.then回調(diào)放入microtask隊(duì)列,同樣的步驟執(zhí)行timer2,打印timer2;這點(diǎn)跟瀏覽器端相差比較大,timers階段有幾個(gè)setTimeout/setInterval都會(huì)依次執(zhí)行,并不像瀏覽器端,每執(zhí)行一個(gè)宏任務(wù)后就去執(zhí)行一個(gè)微任務(wù)(關(guān)于Node與瀏覽器的 Event Loop 差異,下文還會(huì)詳細(xì)介紹)。

3.Micro-Task 與 Macro-Task

Node端事件循環(huán)中的異步隊(duì)列也是分為macro(宏任務(wù))隊(duì)列和 micro(微任務(wù))隊(duì)列。

  • Node端常見的 macro-task 比如:setTimeout、setInterval、 setImmediate、script(整體代碼)、 I/O 操作等。
  • Node端常見的 micro-task 比如: process.nextTick、new Promise().then(回調(diào))等。

4.注意點(diǎn)

(1) setTimeout 和 setImmediate

二者非常相似,區(qū)別主要在于調(diào)用時(shí)機(jī)不同。

  • setImmediate 設(shè)計(jì)在poll階段完成時(shí)執(zhí)行,即check階段;
  • setTimeout 設(shè)計(jì)在poll階段為空閑時(shí),且設(shè)定時(shí)間到達(dá)后執(zhí)行,但它在timer階段執(zhí)行
setTimeout(function timeout () { 
console.log('timeout'); 
},0); 
setImmediate(function immediate () { 
console.log('immediate'); 
}); 
  • 對(duì)于以上代碼來(lái)說(shuō),setTimeout 可能執(zhí)行在前,也可能執(zhí)行在后。
  • 首先 setTimeout(fn, 0) === setTimeout(fn, 1),這是由源碼決定的 進(jìn)入事件循環(huán)也是需要成本的,如果在準(zhǔn)備時(shí)候花費(fèi)了大于 1ms 的時(shí)間,那么在 timer 階段就會(huì)直接執(zhí)行 setTimeout 回調(diào)
  • 如果準(zhǔn)備時(shí)間花費(fèi)小于 1ms,那么就是 setImmediate 回調(diào)先執(zhí)行了

但當(dāng)二者在異步i/o callback內(nèi)部調(diào)用時(shí),總是先執(zhí)行setImmediate,再執(zhí)行setTimeout

const fs = require('fs') 
fs.readFile(__filename, () => { 
 setTimeout(() => { 
 console.log('timeout'); 
 }, 0) 
 setImmediate(() => { 
 console.log('immediate') 
 }) 
}) 
// immediate 
// timeout 

在上述代碼中,setImmediate 永遠(yuǎn)先執(zhí)行。因?yàn)閮蓚€(gè)代碼寫在 IO 回調(diào)中,IO 回調(diào)是在 poll 階段執(zhí)行,當(dāng)回調(diào)執(zhí)行完畢后隊(duì)列為空,發(fā)現(xiàn)存在 setImmediate 回調(diào),所以就直接跳轉(zhuǎn)到 check 階段去執(zhí)行回調(diào)了。

(2) process.nextTick

這個(gè)函數(shù)其實(shí)是獨(dú)立于 Event Loop 之外的,它有一個(gè)自己的隊(duì)列,當(dāng)每個(gè)階段完成后,如果存在 nextTick 隊(duì)列,就會(huì)清空隊(duì)列中的所有回調(diào)函數(shù),并且優(yōu)先于其他 microtask 執(zhí)行。

setTimeout(() => { 
console.log('timer1') 
Promise.resolve().then(function() { 
 console.log('promise1') 
}) 
}, 0) 
process.nextTick(() => { 
console.log('nextTick') 
process.nextTick(() => { 
 console.log('nextTick') 
 process.nextTick(() => { 
 console.log('nextTick') 
 process.nextTick(() => { 
 console.log('nextTick') 
 }) 
 }) 
}) 
}) 
// nextTick=>nextTick=>nextTick=>nextTick=>timer1=>promise1 

五、Node與瀏覽器的 Event Loop 差異

瀏覽器環(huán)境下,microtask的任務(wù)隊(duì)列是每個(gè)macrotask執(zhí)行完之后執(zhí)行。而在Node.js中,microtask會(huì)在事件循環(huán)的各個(gè)階段之間執(zhí)行,也就是一個(gè)階段執(zhí)行完畢,就會(huì)去執(zhí)行microtask隊(duì)列的任務(wù)。

 

 

 

接下我們通過(guò)一個(gè)例子來(lái)說(shuō)明兩者區(qū)別:

setTimeout(()=>{ 
 console.log('timer1') 
 Promise.resolve().then(function() { 
 console.log('promise1') 
 }) 
}, 0) 
setTimeout(()=>{ 
 console.log('timer2') 
 Promise.resolve().then(function() { 
 console.log('promise2') 
 }) 
}, 0) 

瀏覽器端運(yùn)行結(jié)果:timer1=>promise1=>timer2=>promise2

瀏覽器端的處理過(guò)程如下:

 

 

 

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

要看第一個(gè)定時(shí)器執(zhí)行完,第二個(gè)定時(shí)器是否在完成隊(duì)列中。

  • 如果是第二個(gè)定時(shí)器還未在完成隊(duì)列中,最后的結(jié)果為timer1=>promise1=>timer2=>promise2
  • 如果是第二個(gè)定時(shí)器已經(jīng)在完成隊(duì)列中,則最后的結(jié)果為timer1=>timer2=>promise1=>promise2(下文過(guò)程解釋基于這種情況下)

1.全局腳本(main())執(zhí)行,將2個(gè)timer依次放入timer隊(duì)列,main()執(zhí)行完畢,調(diào)用棧空閑,任務(wù)隊(duì)列開始執(zhí)行;

2.首先進(jìn)入timers階段,執(zhí)行timer1的回調(diào)函數(shù),打印timer1,并將promise1.then回調(diào)放入microtask隊(duì)列,同樣的步驟執(zhí)行timer2,打印timer2;

3.至此,timer階段執(zhí)行結(jié)束,event loop進(jìn)入下一個(gè)階段之前,執(zhí)行microtask隊(duì)列的所有任務(wù),依次打印promise1、promise2

Node端的處理過(guò)程如下:

 

 

 

六、總結(jié)

瀏覽器和Node 環(huán)境下Event Loop有所區(qū)別,主要體現(xiàn)在微任務(wù)隊(duì)列的執(zhí)行時(shí)機(jī)不同

  • Node端,microtask 在事件循環(huán)的各個(gè)階段之間執(zhí)行
  • 瀏覽器端,microtask 在事件循環(huán)的 macrotask 執(zhí)行完之后執(zhí)行
推薦 打印 | 錄入:admin | 閱讀:
相關(guān)新聞      
本文評(píng)論   
評(píng)論聲明
  • 尊重網(wǎng)上道德,遵守中華人民共和國(guó)的各項(xiàng)有關(guān)法律法規(guī)
  • 承擔(dān)一切因您的行為而直接或間接導(dǎo)致的民事或刑事法律責(zé)任
  • 本站管理人員有權(quán)保留或刪除其管轄留言中的任意內(nèi)容
  • 本站有權(quán)在網(wǎng)站內(nèi)轉(zhuǎn)載或引用您的評(píng)論
  • 參與本評(píng)論即表明您已經(jīng)閱讀并接受上述條款
-->
在线视频一区二区免费| 亚洲一区二区三区视频在线| 久久久久999| 调教在线观看| 蜜臀av一级做a爰片久久| 韩国美女主播一区| 欧美videosex性欧美黑吊| 成人一级黄色片| eeuss一区二区三区| 性欧美video另类hd尤物| 欧美色精品在线视频| 日韩中文字幕二区| 久久亚洲欧洲| 国产精品男女猛烈高潮激情| 秋霞国产精品| 精品视频一区三区九区| 蜜臀av午夜一区二区三区| 亚洲综合丁香| 国产欧美一区二区三区在线看| 亚洲成人短视频| 日韩欧美激情四射| 黄页网站在线观看| 91网站黄www| 欧美性色黄大片人与善| 夜夜春成人影院| 色综合伊人色综合网站| 77777影视视频在线观看| 亚洲人xxxx| www.中文字幕在线| 视频一区中文字幕国产| 国产精品爽黄69天堂a| 成人av色网站| 日韩精品在线视频| a级毛片免费观看在线| 91精品福利视频| 3dmax动漫人物在线看| 国产欧美精品国产国产专区| 成人免费a级片| 久久99精品国产麻豆婷婷| 欧洲精品一区色| 日本va欧美va欧美va精品| 小说区视频区图片区| 国产99一区视频免费| 亚洲午夜无码av毛片久久| 日本一区二区高清| 国产69精品久久久久孕妇| 亚洲动漫第一页| 性感av在线播放| 91精品国产欧美日韩| 日本高清成人vr专区| 亚洲人成网站777色婷婷| 日本午夜精品久久久久| 性色av一区二区三区| 欧美电影一区| 欧美日韩一区在线观看视频| 成人性生交大片免费看视频在线| 18禁免费无码无遮挡不卡网站| 国产精品毛片高清在线完整版| 色视频www在线播放| 69av一区二区三区| xxx性欧美| www.久久色.com| 久久99精品久久久久久园产越南| 亚洲va欧美va国产综合久久| 日韩不卡免费视频| 国产成人无码精品久久久性色| 欧美国产精品一区二区| 在线播放三级网站| 亚洲激情电影中文字幕| 国产欧美88| 97久久夜色精品国产九色 | 国产在线拍揄自揄拍视频| 日韩成人网免费视频| 精品国产鲁一鲁****| 亚洲精品国产系列| 国产一区一区| 亚洲片av在线| 天堂аⅴ在线最新版在线 | 一区二区三区观看| 成人免费高清在线| 99在线免费观看| 在线综合视频播放| 99视频这里有精品| 91色p视频在线| 国产成人av福利| 日本福利午夜视频在线| 一区二区亚洲精品国产| 自拍日韩欧美| 精品久久久久久久久久中文字幕| 狠狠干狠狠久久| 看片一区二区| 六十路精品视频| 亚洲三级久久久| 欧美影视资讯| 国产精品美女xx| 中文字幕日韩精品一区| 亚洲天堂免费电影| 成人免费福利在线| 国产亚洲欧美日韩在线一区| 97超碰在线公开在线看免费| 国产精品高潮在线| av在线不卡网| hd国产人妖ts另类视频| 91日韩在线播放| 中文字幕中文乱码欧美一区二区| 第一福利在线视频| 国产传媒一区二区三区| 亚洲天堂av一区| 久久国产三级| 亚洲综合五月天| 欧美日韩国产一级二级| 成人羞羞网站| 99热在线看| 成人免费av电影| 91精品国产综合久久香蕉| 成人av先锋影音| 678在线观看视频| 国产在线精品播放| www.欧美精品一二区| 婷婷在线播放| 成人免费91在线看| 亚洲日本va午夜在线影院| 日韩久久99| 男女裸体影院高潮| 亚洲成人1234| 日韩专区欧美专区| 成人免费看片| 99久久伊人精品影院| 亚洲二区在线视频| 伊人久久大香线蕉| 97视频网站| 欧美二区在线播放| 成人黄色一级视频| 日韩影片中文字幕| 亚洲欧美国产精品桃花| 日韩免费看网站| 亚洲女同在线| 色的视频在线免费看| 国产伦精品一区二区| 欧美色图免费看| 亚洲精品专区| 国产人成网在线播放va免费| 久久另类ts人妖一区二区| 欧美美女一区二区三区| 精品动漫3d一区二区三区免费| 风间由美一区| 久久久精彩视频| 欧美xxxxxxxx| 狠狠色丁香久久婷婷综合丁香| 国产资源在线观看入口av| 神马影院午夜我不卡影院| 欧美精品一区二区三区在线播放| 狂野欧美性猛交xxxx巴西| 欧美性爽视频| 蜜臀av性久久久久蜜臀av| 中文字幕精品国产| 国产丝袜美腿一区二区三区| 美女一区二区在线观看| 激情小说激情视频| 亚洲一区二区三区久久| 欧美一区二区三区在线| 精品无人码麻豆乱码1区2区 | 国产精品视频一区二区久久| 日韩在线视频网站| 天天久久综合| 欧洲色大大久久| 亚洲夜间福利| 免费在线观看av网站| 精品国产一区二区三区麻豆小说 | 亚洲欧美激情插| av一区二区在线播放| 青青青草原在线| 成人一区二区三区四区| 欧美一区午夜视频在线观看| 久久精品噜噜噜成人av农村| 日本成人在线网站| 国产对白在线| 51成人做爰www免费看网站| 日韩欧美在线观看一区二区三区| 国产精品一区二区久久不卡| 在线视频亚洲欧美中文| 九色在线91| 国产欧美一区二区三区另类精品 | 国产三级一区二区三区| 亚洲福利天堂| 日韩子在线观看| 四虎精品欧美一区二区免费| 欧美国产日产韩国视频| 岛国视频午夜一区免费在线观看| 免费在线亚洲| 亚洲一区二区三区日本久久九| 亚洲日本伦理| 欧美 另类 交| 国产精品久久久91| 亚洲精品久久久久久久久久久久久 | 亚洲综合丁香| 欧美成人精品一级| 日本高清在线观看wwwww色| 国产美女网站在线观看| 99电影在线观看|