1. 程式人生 > >瀏覽器的event loop和node的event loop

瀏覽器的event loop和node的event loop

1.什麼是event loop

event loops也就是事件迴圈,它是為了協調事件(event),使用者互動(user interaction),指令碼(script),渲染(rendering),網路(networking),使用者代理(user agent)的工作而產生的一個機制。

2.JavaScript的執行機制

2.1 單執行緒的JavaScript

JavaScript語言的一大特點就是單執行緒,也就是說在同一時間只做同一件事。這是基於js的執行環境決定的,因為在瀏覽器中,有許多的dom操作,如果在同一時間操作一個dom,很容易造成混亂,所以為了避免發生同一時間操作同一dom的情況,js選擇只用一個主執行緒執行程式碼,來保證程式執行的一致性,單執行緒的特點也應用到了node中。

2.2 JavaScript中的任務和佇列

JavaScript是單執行緒的,也就意味著所有任務需要排隊,前一個任務執行完,才能執行下一個任務,但是因為IO裝置(輸入輸出裝置)很慢(比如Ajax從網路讀取資料),不得不等待結果返回之後才能繼續,這樣的執行效率很慢。
於是分成了兩種任務來處理,同步任務和非同步任務。
同步任務是指在主執行緒排隊的任務,只有前面的任務執行完之後才執行後面的任務。
非同步任務指的是任務不進入主執行緒,而進入到一個任務佇列(task queue),主執行緒的任務可以繼續往後執行,而在任務佇列裡的非同步任務執行完會通知主執行緒。

3.瀏覽器的event loop

3.1執行棧與事件佇列

當javascript程式碼執行的時候會將不同的變數存於記憶體中的不同位置:堆(heap)和棧(stack)中來加以區分。其中,堆裡存放著一些物件。而棧中則存放著一些基礎型別變數以及物件的指標。當所有所有同步任務都在主執行緒上執行時,這些任務被排列在一個單獨的地方,形成一個執行棧

當瀏覽器js引擎解析這段程式碼時,會將同步任務順序加入執行棧中依次執行,當遇到非同步任務時並不會一直等待非同步任務返回結果再執行後面的任務,而是將非同步任務掛起,繼續執行同步任務,當非同步任務返回結果時,將非同步任務的回撥事件加入到一個事件佇列(Task Queue)當中去,這個事件佇列裡的任務並不會立即執行,而是等同步任務全部執行完,再依次執行事件佇列裡的事件。

依次執行同步任務,完成後依次執行事件佇列,完成後再去執行同步任務,這樣形成了一個迴圈,就是事件迴圈(Event Loop)。

3.2巨集任務(macro task)與微任務(micro task)

非同步任務又分為巨集任務與微任務兩種,微任務並不是老老實實的按照事件佇列的順序去執行,而是按照microTask—>macroTask的順序去執行,先執行完佇列中所有的microTask再去執行macroTask

巨集任務和微任務的分類

  • MacroTask: script(整體程式碼), setTimeout, setInterval, setImmediate(node獨有), I/O, UI rendering

  • MicroTask: process.nextTick(node獨有), Promises, Object.observe(廢棄), MutationObserver

舉個例子
setTimeout(()=>{
    console.log(1)
})

Promise.resolve().then(function() {
    console.log(2)
})
console.log(3)

執行結果是:3 2 1
這是因為事件迴圈的順序是:同步程式碼=>微任務=>巨集任務

4.node的event loop

  • timers: 這個階段執行定時器佇列中的回撥如 setTimeout() 和 setInterval()。

  • I/O callbacks: 這個階段執行幾乎所有的回撥。但是不包括close事件,定時器和setImmediate()的回撥。

  • idle, prepare: 這個階段僅在內部使用,可以不必理會。

  • poll: 等待新的I/O事件,node在一些特殊情況下會阻塞在這裡。

  • check: setImmediate()的回撥會在這個階段執行。

  • close callbacks: 例如socket.on(‘close’, …)這種close事件的回撥。


event loop的每一次迴圈都需要依次經過上述的階段。 每個階段都有自己的callback佇列,每當進入某個階段,都會從所屬的佇列中取出callback來執行,當佇列為空或者被執行callback的數量達到系統的最大數量時,進入下一階段。這六個階段都執行完畢稱為一輪迴圈。

舉個例子(1)
瀏覽器與Node執行順序的區別
setTimeout(()=>{
    console.log('timer1')

    Promise.resolve().then(function() {
        console.log('promise1')
    })
})

setTimeout(()=>{
    console.log('timer2')

    Promise.resolve().then(function() {
        console.log('promise2')
    })
})

瀏覽器輸出:
time1
promise1
time2
promise2
因為promise是microtask,所以當第一個setTimeout執行完之後,先執行promise。

Node輸出:
time1
time2
promise1
promise2
因為time1和time2都在timers階段,所以先執行timers,promise的回撥被加入到了microtask佇列,等到timers階段執行完畢,在去執行microtask佇列。

舉個例子(2)
MicroTask佇列與MacroTask佇列
setTimeout(function () {
   console.log(1);
});
console.log(2);
process.nextTick(() => {
   console.log(3);
});
new Promise(function (resolve, rejected) {
   console.log(4);
   resolve()
}).then(res=>{
   console.log(5);
})
setImmediate(function () {
   console.log(6)
})
console.log('end');

node輸出的順序是
2
4
end
3
5
1
6
首先執行的是同步任務中的2 4 end,然後是microTask佇列中的process.nextTick:3、promise.then:5,最後是macroTask佇列中的setTimeout:1、setImmediate:6,由於Timer優於Check階段,所以先1後6。

相關推薦

瀏覽器event loopnode的event loop

1.什麼是event loop event loops也就是事件迴圈,它是為了協調事件(event),使用者互動(user interaction),指令碼(script),渲染(rendering),網路(networking),使用者代理(user age

JavaScript Event Loop微任務、宏任務

nextTick hub mic mozilla 執行過程 函數調用 所有 git 全局 為什麽JavaScript是單線程? JavaScript的一大特點就是單線程, 同一時間只能做一件事情,主要和它的用途有關, JavaScript主要是控制和用戶的交互以及操作DOM

Block Nested-Loop Batched Key Access

關聯 extra spa pla key 如果 過程 算法 man 官方文檔:https://dev.mysql.com/doc/refman/5.7/en/bnl-bka-optimization.html BNL和BKA是MySQL 表關聯的兩種關聯算法 比如t1、t2

彙編 --實現一個迴圈程式 loopcx

assume cs:code,ds:data,ss:stack data segment             db'welcome to masm!';定義要顯示的字串(共16位元組)             db 02H,24H,71H;定義字元的屬性 data en

pl/sql中的控制語句應用: 迴圈語句 loopfor

LOOP   要執行的語句;   EXIT WHEN <條件語句> /*條件滿足,退出迴圈語句*/END LOOP;  例:DECLARE     int NUMBER(2) :=0; BEGIN    LOOP       int := int + 1;  

oracle hash joinnested loop下的驅動表相關測試

Oracle 驅動表 Oracle驅動表也叫做外部表,也叫外層表,是在多表關聯查詢中首先遍歷的表,驅動表的每一行都要到另一個表中尋找相應的記錄,然後計算返回最終資料。 驅動表的概念只在nested l

Looper.prepare()Looper.loop(),在子執行緒中更新UI

當子執行緒想直接更新UI時,例如進行Toast提示。 可以先Looper.prepare(),然後Looper.loop(),程式碼如下(加黑處): public class CrashHandler implements UncaughtExceptionHandler

Kotlin入門篇(五),LoopRange,Kotlin中區間的定義遍歷

Loop和Range Kotlin迴圈的使用和區間的定義和Java有很大的不同,如: fun main(args: Array<String>) { var nums = 1..100 //[1,100] for (num i

Android-Looper類,Looper.prepare()Looper.loop()

Android中的Looper類,是用來封裝訊息迴圈和訊息佇列的一個類,用於在android執行緒中進行訊息處理。handler其實可以看做是一個工具類,用來向訊息佇列中插入訊息的。 (1) Looper類用來為一個執行緒開啟一個訊息迴圈。     預設情況下andro

Looper.prepare()Looper.loop()詳解

Android中的Looper類,是用來封裝訊息迴圈和訊息佇列的一個類,用於在android執行緒中進行訊息處理。handler其實可以看做是一個工具類,用來向訊息佇列中插入訊息的。    (1) Looper類用來為一個執行緒開啟一個訊息迴圈。 預設情況下android中

chrome瀏覽器中解決embed標籤 loop="true" 背景音樂無法迴圈的問題。

今天試了下在html網頁中加入背景音樂並設定為迴圈播放。一開始用<embed>標籤,設定loop="true", 但是結果發現在IE瀏覽器可以,但是在chrome瀏覽器卻無法實現迴圈,播放完一次自動停止了。程式碼如下:<embed src="1.mp3" 

Run loopThread

Run-loop是什麼? 首先考慮這個問題:你的Cocoa程式大部分的時間什麼都沒做,更具體點,是在等待輸入。然而,一旦你觸控式螢幕幕,相應的事件被觸發,就可能會執行你的一段事件處理程式碼。同理,socket中返回一些資料,或者計時器觸發等也是一樣的情況。而且更重要的是,一旦觸發事件的程式碼執行完,程

瀏覽器的解析執行過程

們的 由於 繼續 動畫 table 就會 內嵌 cnblogs 內嵌腳本 當瀏覽器獲得一個html文件時,會“自上而下”加載,並在加載過程中進行解析渲染。 解析: 1. 瀏覽器會將HTML解析成一個DOM樹(display:none,visibility:hidden)。

瀏覽器加載渲染html的順序

tle 幫助 .html bsp 發現 知識 lan 以及 前端 在寫代碼的時候,發現若將javasript代碼寫在html前面,會遇到獲取不到你想要的元素的問題,調試了好久,然後才發現是因為瀏覽器還沒有加載html中相應的元素,這當然獲取不到,於是將script代碼改

Javascript中獲取瀏覽器類型操作系統版本等客戶端信息常用代碼

cin nav coo temp undefined light safari macintosh else /** * @author hechen */ var gs = { /**獲得屏幕寬度**/ ScreenWidth: function () {

阻止事件冒泡,阻止默認事件,event.stopPropagation()event.preventDefault(),return false的區別

attr htm pre 點擊 操作 連接 com spa ati 1.event.stopPropagation()方法 這是阻止事件的冒泡方法,不讓事件向documen上蔓延,但是默認事件任然會執行,當你掉用這個方法的時候,如果點擊一個連接,這個連接仍然會被打開, 2.

瀏覽器Request HeaderResponse Header的內容

編碼方式 all nco 下載 chunk posit .com lang 支持 文章標簽:瀏覽器請求頭,響應頭 1)請求(客戶端->服務端[request]) GET(請求的方式) /newcoder/hello.html(請求的目標資源) HTTP/1.1

瀏覽器緩存壓縮優化技術

工具 服務器 獲取 內容修改 exp 完整 size 靜態 gzip 一、HTTP緩存機制緩存分類1、200 from cache:直接從本地緩存中獲取響應,最快速,最省流量,因為根本沒有向服務器發送請求;2、304 NOT Modified:協商緩存,瀏覽器在本地沒有命中

C# 用XiliumCefGlue做瀏覽器,JSC#相互調用

需要 更改 net 執行 關於 我的電腦 thread alt 添加 原文:C# 用XiliumCefGlue做瀏覽器,JS和C#相互調用 版權聲明:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.ne

NodeJs中的http-server的使用--解決chrome瀏覽器執行htmljs檔案的時候,無法呼叫本地的檔案

  一、環境:已經安裝了nodeJS。 二、安裝http-server:    開啟cmd --》 輸入  npm install http-server -g  注意:需要-g ,否則會出現錯誤,並且點選執行start.bat的時候