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