摘要:瀏覽器和中并不一樣,瀏覽器的是在中定義的規(guī)范,而中則由庫實(shí)現(xiàn)。整個(gè)的這種運(yùn)行機(jī)制又稱為事件循環(huán)例子了解瀏覽器的后,查看下面例子,猜測瀏覽器是怎么輸出的瀏覽器輸出中的在內(nèi)部有這樣一個(gè)事件環(huán)機(jī)制。在啟動時(shí)會初始化事件環(huán)。執(zhí)行和中到期的。
大家都知道,javascript是一門單線程語言,因此為了實(shí)現(xiàn)主線程的不阻塞,Event Loop這樣的方案應(yīng)運(yùn)而生。
瀏覽器和node中Event loop并不一樣,瀏覽器的Event loop是在HTML5中定義的規(guī)范,而node中則由libuv庫實(shí)現(xiàn)。
瀏覽器中的Event loop
所有同步任務(wù)都在主線程上執(zhí)行,形成一個(gè)執(zhí)行棧
主線程之外,還存在一個(gè)任務(wù)隊(duì)列。
任務(wù)隊(duì)列分為macro-task(宏任務(wù))和micro-task(微任務(wù))。
macro-task(宏任務(wù)): setTimeout, setInterval, setImmediate, I/O等
micro-task(微任務(wù)): process.nextTick, 原生Promise(有些實(shí)現(xiàn)的promise將then方法放到了宏任務(wù)中),Object.observe(已廢棄), MutationObserver等
整個(gè)最基本的Event Loop如圖所示:
具體過程:
瀏覽器中,先執(zhí)行當(dāng)前棧,執(zhí)行完主執(zhí)行線程中的任務(wù)。
取出Microtask微任務(wù)隊(duì)列中任務(wù)執(zhí)行直到清空。
取出Macrotask宏任務(wù)中 一個(gè) 任務(wù)執(zhí)行。
檢查Microtask微任務(wù)中有沒有任務(wù),如果有任務(wù)執(zhí)行直到清空。
重復(fù)3和4。
整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))
例子
了解瀏覽器的Event loop后,查看下面例子,猜測瀏覽器是怎么輸出的
console.log(1); console.log(2); setTimeout(function(){ console.log("setTimeout1"); Promise.resolve().then(function(){ console.log("Promise") }) }) setTimeout(function(){ console.log("setTimeout2"); }) //瀏覽器輸出:1 2 setTimeout1 Promise setTimeout2
node中的Event loop
在libuv內(nèi)部有這樣一個(gè)事件環(huán)機(jī)制。在node啟動時(shí)會初始化事件環(huán)。
node中的event loop分為6個(gè)階段,不同于瀏覽器的是,這里每一個(gè)階段都對應(yīng)一個(gè)事件隊(duì)列,node會在當(dāng)前階段中的全部任務(wù)執(zhí)行完,清空NextTick Queue,清空Microtask Queue,再執(zhí)行下一階段。
在node.js里,process 對象代表node.js應(yīng)用程序,可以獲取應(yīng)用程序的用戶,運(yùn)行環(huán)境等各種信息。process.nextTick()方法將 callback 添加到next tick 隊(duì)列,并且nextTick優(yōu)先級比promise等microtask高。
timers:執(zhí)行setTimeout() 和 setInterval()中到期的callback。
I/O callbacks:上一輪循環(huán)中有少數(shù)的I/Ocallback會被延遲到這一輪的這一階段執(zhí)行
idle, prepare:隊(duì)列的移動,僅內(nèi)部使用
poll:最為重要的階段,執(zhí)行I/O callback,在適當(dāng)?shù)臈l件下會阻塞在這個(gè)階段
check:執(zhí)行setImmediate的callback
close callbacks:執(zhí)行close事件的callback,例如socket.on("close",func)
例子
查看下面例子加深對event loop的理解
在node執(zhí)行下面代碼,發(fā)現(xiàn)每次執(zhí)行先后順序不一樣,因?yàn)閚ode需要啟動時(shí)間,執(zhí)行過程中setTimeout可能到時(shí)間了也可能沒到時(shí)間,所以這個(gè)先后順序取決于node的執(zhí)行時(shí)間。
setTimeout(function(){ console.log("timeout") }) setImmediate(function(){ console.log("immediate") })
i/o操作階段完成后,會走check階段,所以setImmediate會優(yōu)先走
let fs=require("fs"); fs.readFile("./1.log",function(){ console.log("fs"); setTimeout(function(){ console.log("timeout") }) setImmediate(funciton(){ console.log("setTimmediate") }) })
nextTick應(yīng)用場景
function Fn(){ this.arrs; process.nextTick(()=>{ //根據(jù)nextTick的特性,可以先賦值,再在下一個(gè)隊(duì)列中使用 this.arrs(); }) } Fn.prototype.then=function(){ this.arrs=function(){console.log(1)} } let fn=new Fn(); fn.then(); //注意:nextTick千萬不要寫遞歸,不然會造成死循環(huán)。可以放一些比setTimeout優(yōu)先執(zhí)行的任務(wù)
總結(jié)
同一個(gè)上下文下,MicroTask微任務(wù)會比MacroTask宏任務(wù)先運(yùn)行。
瀏覽器是先取出一個(gè)MacroTask宏任務(wù)執(zhí)行,再執(zhí)行MicroTask微任務(wù)中的所有任務(wù)。Node是按照六個(gè)階段執(zhí)行,每個(gè)階段切換時(shí),再執(zhí)行MicroTask微任務(wù)隊(duì)列
同個(gè)MicroTask隊(duì)列下process.tick()會優(yōu)于Promise
setImmdieate()和setTimeout(),如果他們在異步i/o callback之外調(diào)用(在i/o內(nèi)調(diào)用因?yàn)橄乱浑A段為check階段),其執(zhí)行先后順序是不確定的,需要看loop的執(zhí)行前的耗時(shí)情況。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/93749.html
摘要:如果當(dāng)前沒有事件也沒有定時(shí)器事件,則返回。相關(guān)資料關(guān)于的架構(gòu)及設(shè)計(jì)思路的事件討論了使用線程池異步運(yùn)行代碼。下一篇初窺事件機(jī)制的實(shí)現(xiàn)二中定時(shí)器的實(shí)現(xiàn) 在瀏覽器中,事件作為一個(gè)極為重要的機(jī)制,給予JavaScript響應(yīng)用戶操作與DOM變化的能力;在Node.js中,事件驅(qū)動模型則是其高并發(fā)能力的基礎(chǔ)。 學(xué)習(xí)JavaScript也需要了解它的運(yùn)行平臺,為了更好的理解JavaScript的事...
摘要:新加了一個(gè)微任務(wù)和一個(gè)宏任務(wù)在當(dāng)前執(zhí)行棧的尾部下一次之前觸發(fā)回調(diào)函數(shù)。階段這個(gè)階段主要執(zhí)行一些系統(tǒng)操作帶來的回調(diào)函數(shù),如錯(cuò)誤,如果嘗試鏈接時(shí)出現(xiàn)錯(cuò)誤,一些會把這個(gè)錯(cuò)誤報(bào)告給。 JavaScript引擎又稱為JavaScript解釋器,是JavaScript解釋為機(jī)器碼的工具,分別運(yùn)行在瀏覽器和Node中。而根據(jù)上下文的不同,Event loop也有不同的實(shí)現(xiàn):其中Node使用了libu...
摘要:如果沒到毫秒,那么階段就會跳過,進(jìn)入階段,先執(zhí)行的回調(diào)函數(shù)。參考文檔什么是瀏覽器的事件循環(huán)不要混淆和瀏覽器中的定時(shí)器詳解瀏覽器和不同的事件循環(huán)深入理解事件循環(huán)機(jī)制篇中的執(zhí)行機(jī)制 最近對Event loop比較感興趣,所以了解了一下。但是發(fā)現(xiàn)整個(gè)Event loop盡管有很多篇文章,但是沒有一篇可以看完就對它所有內(nèi)容都了解的文章。大部分的文章都只闡述了瀏覽器或者Node二者之一,沒有對比...
摘要:事件觸發(fā)線程主要負(fù)責(zé)將準(zhǔn)備好的事件交給引擎線程執(zhí)行。它將不同的任務(wù)分配給不同的線程,形成一個(gè)事件循環(huán),以異步的方式將任務(wù)的執(zhí)行結(jié)果返回給引擎。 Fundebug經(jīng)作者浪里行舟授權(quán)首發(fā),未經(jīng)同意請勿轉(zhuǎn)載。 前言 本文我們將會介紹 JS 實(shí)現(xiàn)異步的原理,并且了解了在瀏覽器和 Node 中 Event Loop 其實(shí)是不相同的。 一、線程與進(jìn)程 1. 概念 我們經(jīng)常說 JS 是單線程執(zhí)行的,...
摘要:前言前幾天在理解的事件環(huán)機(jī)制中引發(fā)了我對瀏覽器里的好奇。接下來理解瀏覽器中的,先看一張圖堆和棧堆是用戶主動請求而劃分出來的內(nèi)存區(qū)域,比如你,就是將一個(gè)對象存入堆中,可以理解為存對象。廢話不多說,直接上圖個(gè)人理解。參考資料運(yùn)行機(jī)制詳解再談 前言 前幾天在理解node的事件環(huán)機(jī)制中引發(fā)了我對瀏覽器里Event Loop的好奇。我們都知道javascript是單線程的,任務(wù)是需要一個(gè)一個(gè)按順...
閱讀 1707·2021-10-09 09:44
閱讀 3269·2021-09-27 13:36
閱讀 1527·2021-09-22 15:33
閱讀 1282·2021-09-22 15:23
閱讀 1168·2021-09-06 15:02
閱讀 1706·2019-08-29 16:14
閱讀 2913·2019-08-29 15:26
閱讀 2414·2019-08-28 18:08