摘要:什么是事件循環盡管是單線程的,事件循環機制,通過在合適的時候把操作交給系統內核,從而允許執行非阻塞的操作當操作完成時,內核告知,合適的回調函數會被加入輪詢隊列,最終被執行。結果長時間的運行回調函數允許運行事件比的閾值更長。
什么是事件循環(event loop)?
盡管js是單線程的,事件循環機制,通過在合適的時候把操作交給系統內核,從而允許node執行非阻塞的io操作
當操作完成時,內核告知node.js,合適的回調函數會被加入輪詢隊列,最終被執行。
Node.js啟動的時候,初始化event loop,處理提供的腳本,腳本中可能調用異步API,調度timers,或者調用process.nextTick(),然后處理event loop
下圖是簡化的事件循環操作順序圖overview
┌───────────────────────┐ ┌─>│ timers │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ I/O callbacks │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ │ │ idle, prepare │ │ └──────────┬────────────┘ ┌───────────────┐ │ ┌──────────┴────────────┐ │ incoming: │ │ │ poll │<─────┤ connections, │ │ └──────────┬────────────┘ │ data, etc. │ │ ┌──────────┴────────────┐ └───────────────┘ │ │ check │ │ └──────────┬────────────┘ │ ┌──────────┴────────────┐ └──┤ close callbacks │ └───────────────────────┘
圖中每個box就是一個phase,每個phase有一個先進先出的回調函數的隊列,
event loop進入了一個phase,就會執行phase中所有的操作,然后執行回調函數,直到隊列耗盡了,或者回調函數執行數量到達最大數,接下來就去下一個phase
因為任何一個操作都可能調度更多的操作,而且poll phase中新的事件由內核排隊,所以正在輪詢的事件在被處理的時候,poll事件們可能會排隊。
結果:長時間的運行回調函數允許poll phase運行事件比timer的閾值更長。
timers:執行由setTimeout() and setInterval()調度的回調函數
I/O callbacks:執行所有的回調函數,除了 close callbacks(由timers,setImmediate()調度)
idle, prepare:內部使用
poll:獲取新的io事件,當合適的時候,node會阻塞在這里
check: setImmediate()回調函數會在這里調用
close callbacks: e.g. socket.on("close", ...)
每次運行event loop,node檢查是否有對任何異步io或者timers的等待,沒有就關閉
Phases in Detail(各階段細述) timerstimers指定閾值(threshold)之后,會執行回調函數,但threshold不是執行回調函數的確切時間(只是最短時間)。
timers回調函數一旦可以執行了就會被執行。然而操作系統的調度或者其他的回調函數可能推遲它的執行。
由poll phase來控制什么時候timers被執行
var fs = require("fs"); function someAsyncOperation (callback) { // Assume this takes 95ms to complete fs.readFile("/path/to/file", callback); } var timeoutScheduled = Date.now(); setTimeout(function () { var delay = Date.now() - timeoutScheduled; console.log(delay + "ms have passed since I was scheduled"); }, 100); // do someAsyncOperation which takes 95 ms to complete someAsyncOperation(function () { var startCallback = Date.now(); // do something that will take 10ms... while (Date.now() - startCallback < 10) { ; // do nothing } });
一開始timer被調度,里面的回調函數執行log。
然后事件循環進入poll phase,此時隊列是空的(因為fs.readFile()沒有完成),所以就會等著,直到最早的timer的閾值(100)到時間,等了95 ms(還沒到,畢竟定的是100),fs.readFile() 這個時候完成了,所以它的回調函數就回被加poll的隊列并且被執行(執行10s),當回調函數完成了,隊列又空了,所以,event loop將會看到timer的閾值(100)已經到了,
然后回到timers這個phase去執行timers的回調函數,也就是,打印出105秒
為了防止poll phase 獨占耗盡 event loop,libuv 也有一個最大值(基于系統),會在超過最大值之前停止輪詢更多的事件。
I/O callbacks為系統操作(比如tcp錯誤類型)執行回調函數
當tcp socket嘗試連接時接收到ECONNREFUSED,類unix系統將會想報道錯誤,要會在這個phase排隊執行。
poll phase有兩個功能
為到了時間的timers執行腳本,然后
處理poll隊列的事件
當event loop 進入poll phase且沒有timers被調度,下面的事情會發生
poll不空,
通過回調函數隊列迭代的執行
poll棧是空的
如果腳本已經被setImmediate()調度,事件循環將會終止poll phase,到check phase去執行那些被調度的腳本
等著回調函數被加進隊列,然后立馬執行它
一旦poll空了,event loop將回檢查timers有沒有thresholds到了,有的話,wrap back to the timers phase,然后執行timers的回調函數
特別的 timer
close callbacks setImmediate and setTimeout()在poll完成以后執行
在最小事件之后執行
執行順序:
依賴于調用的上下文
如果都在main module ,事件會被進程的性能限制(被其他應用影響)
not within an I/O cycle:不確定的
within an I/O cycle:immediate總是先(更好)
// timeout_vs_immediate.js setTimeout(function timeout () { console.log("timeout"); },0); setImmediate(function immediate () { console.log("immediate"); });
// timeout_vs_immediate.js var fs = require("fs") fs.readFile(__filename, () => { setTimeout(() => { console.log("timeout") }, 0) setImmediate(() => { console.log("immediate") }) })
The Node.js Event Loop, Timers
參考:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81744.html
摘要:前沿是基于引擎的運行環境具有事件驅動非阻塞等特點結合具有網絡編程文件系統等服務端的功能用庫進行異步事件處理線程的單線程含義實際上說的是執行同步代碼的主線程一個程序的啟動不止是分配了一個線程,而是我們只能在一個線程執行代碼當出現資源調用連接等 前沿 Node.js 是基于V8引擎的javascript運行環境. Node.js具有事件驅動, 非阻塞I/O等特點. 結合Node API, ...
摘要:的單線程,與它的用途有關。特點的顯著特點異步機制事件驅動。隊列的讀取輪詢線程,事件的消費者,的主角。它將不同的任務分配給不同的線程,形成一個事件循環,以異步的方式將任務的執行結果返回給引擎。 這兩天跟同事同事討論遇到的一個問題,js中的event loop,引出了chrome與node中運行具有setTimeout和Promise的程序時候執行結果不一樣的問題,從而引出了Nodejs的...
摘要:概述本文主要介紹了我對的一些核心特性的理解,包括架構特點機制核心模塊與簡單應用。在此期間,主線程繼續執行其他任務。延續了瀏覽器端單線程,只用一個主線程執行,不斷循環遍歷事件隊列,執行事件。 原文地址在我的博客,轉載請注明來源,謝謝! node是在前端領域經常看到的詞。node對于前端的重要性已經不言而喻,掌握node也是作為合格的前端工程師一項基本功了。知道node、知道后端的一些東西...
摘要:如果當前沒有事件也沒有定時器事件,則返回。相關資料關于的架構及設計思路的事件討論了使用線程池異步運行代碼。下一篇初窺事件機制的實現二中定時器的實現 在瀏覽器中,事件作為一個極為重要的機制,給予JavaScript響應用戶操作與DOM變化的能力;在Node.js中,事件驅動模型則是其高并發能力的基礎。 學習JavaScript也需要了解它的運行平臺,為了更好的理解JavaScript的事...
摘要:當某個執行完畢時,將以事件的形式通知執行操作的線程,線程執行這個事件的回調函數。為了處理異步,線程必須有事件循環,不斷的檢查有沒有未處理的事件,依次予以處理。另外,單線程帶來的好處,操作系統完全不再有線程創建銷毀的時間開銷。 前言 如果你有一定的前端基礎,比如 HTML、CSS、JavaScript、jQuery;那么,Node.js 能讓你以最低的成本快速過渡成為一個全棧工程師(我稱...
摘要:它是在的基礎上改進的一種方案,通過對文件描述符上的事件狀態進行判斷。檢索新的事件執行與相關的回調幾乎所有情況下,除了關閉的回調函數,它們由計時器和排定的之外,其余情況將在此處阻塞。執行事件的,例如或者。 前言 學習Node就繞不開異步IO, 異步IO又與事件循環息息相關, 而關于這一塊一直沒有仔細去了解整理過, 剛好最近在做項目的時候, 有了一些思考就記錄了下來, 希望能盡量將這一塊的...
閱讀 2883·2021-11-24 09:39
閱讀 2455·2019-08-30 15:53
閱讀 3025·2019-08-30 13:47
閱讀 1296·2019-08-30 12:50
閱讀 1481·2019-08-29 16:31
閱讀 2642·2019-08-29 13:14
閱讀 1559·2019-08-29 10:55
閱讀 790·2019-08-26 13:32