日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

node mysql 事件循环_NodeJs 的 Event loop 事件循环机制详解

發(fā)布時(shí)間:2024/9/19 数据库 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 node mysql 事件循环_NodeJs 的 Event loop 事件循环机制详解 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

什么是事件輪詢

事件循環(huán)是 Node.js 處理非阻塞 I/O 操作的機(jī)制——盡管 JavaScript 是單線程處理的——當(dāng)有可能的時(shí)候,它們會(huì)把操作轉(zhuǎn)移到系統(tǒng)內(nèi)核中去。

下面的圖表顯示了事件循環(huán)的概述以及操作順序。

┌───────────────────────────┐

┌─>│ timers │

│ └─────────────┬─────────────┘

│ ┌─────────────┴─────────────┐

│ │ IO / callbacks │

│ └─────────────┬─────────────┘

│ ┌─────────────┴─────────────┐

│ │ idle, prepare │

│ └─────────────┬─────────────┘ ┌───────────────┐

│ ┌─────────────┴─────────────┐ │ incoming: │

│ │ poll │

│ └─────────────┬─────────────┘ │ data, etc. │

│ ┌─────────────┴─────────────┐ └───────────────┘

│ │ check │

│ └─────────────┬─────────────┘

│ ┌─────────────┴─────────────┐

└──┤ close callbacks │

└───────────────────────────┘

三大關(guān)鍵階段

timer:執(zhí)行定時(shí)器時(shí),如 setTimeout、setInterval,在 timers 階段執(zhí)行

poll:異步操作,比如文件I/O,網(wǎng)絡(luò)I/O等,通過(guò)'data'、 'connect'等事件通知 JS 主線程并執(zhí)行回調(diào)的,此階段就是 poll 輪詢階段

check:這是一個(gè)比較簡(jiǎn)單的階段,直接執(zhí)行 setImmdiate 的回調(diào)。

注意,若 2 階段結(jié)束后,當(dāng)前存在到時(shí)間的定時(shí)器,那么拿出來(lái)執(zhí)行,eventLoop 將再回到 timer 階段

階段流程概述

timers: 本階段執(zhí)行已經(jīng)安排的 setTimeout() 和 setInterval() 的回調(diào)函數(shù)

IO / callbacks: 執(zhí)行 I/O 異常的回調(diào),如TCP 連接遇到 ECONNREFUSED

idle, prepare: 僅系統(tǒng)內(nèi)部使用,只是表達(dá)空閑、預(yù)備狀態(tài)(第2階段結(jié)束,poll 未觸發(fā)之前)

poll: 檢索新的 I/O 事件;執(zhí)行與 I/O 相關(guān)的回調(diào)(幾乎所有情況下,除了關(guān)閉的回調(diào)函數(shù)),node 將在此處阻塞。

check: setImmediate() 回調(diào)函數(shù)在這里執(zhí)行.

close callbacks: 一些準(zhǔn)備關(guān)閉的回調(diào)函數(shù),如:socket.on('close', ...)

在每次運(yùn)行的事件循環(huán)之間,Node.js 檢查它是否在等待任何異步 I/O 或計(jì)時(shí)器,如果沒有的話,則關(guān)閉干凈。

timers

timers 指定 可執(zhí)行所提供回調(diào) 的 時(shí)間閾值,poll 階段 控制何時(shí)定時(shí)器執(zhí)行。

一旦 poll queue 為空,事件循環(huán)將檢查 已達(dá)到時(shí)間閾值的timer計(jì)時(shí)器。如果一個(gè)或多個(gè)計(jì)時(shí)器已準(zhǔn)備就緒,則事件循環(huán)將回到 timer 階段以執(zhí)行這些計(jì)時(shí)器的回調(diào)

pending callbacks

此階段對(duì)某些系統(tǒng)操作(如 TCP 錯(cuò)誤類型)執(zhí)行回調(diào)。例如,如果 TCP 套接字在嘗試連接時(shí)接收到 ECONNREFUSED,則某些 *nix 的系統(tǒng)希望等待報(bào)告錯(cuò)誤。這將被排隊(duì)以在 pending callbacks 階段執(zhí)行。

poll

輪詢 階段有兩個(gè)重要的功能:

計(jì)算應(yīng)該阻塞和 poll I/O 的時(shí)間。

然后,處理 poll 隊(duì)列里的事件。

當(dāng)事件循環(huán)進(jìn)入 poll階段且 timers scheduled,將發(fā)生以下兩種情況之一:

if the poll queue is not empty, 事件循環(huán)將循環(huán)訪問其回調(diào)隊(duì)列并同步執(zhí)行它們,直到隊(duì)列已用盡,或者達(dá)到了與系統(tǒng)相關(guān)的硬限制

If the poll queue is empty,還有兩件事發(fā)生

如果腳本已按 setImmediate() 排定,則事件循環(huán)將結(jié)束 輪詢 階段,并繼續(xù) 檢查 階段以執(zhí)行這些計(jì)劃腳本。

如果腳本尚未按 setImmediate()排定,則事件循環(huán)將等待回調(diào)添加到隊(duì)列中,然后立即執(zhí)行。

一旦 poll queue 為空,事件循環(huán)將檢查 已達(dá)到時(shí)間閾值的timer計(jì)時(shí)器。如果一個(gè)或多個(gè)計(jì)時(shí)器已準(zhǔn)備就緒,則事件循環(huán)將回到 timer 階段以執(zhí)行這些計(jì)時(shí)器的回調(diào)。

check

通常,在執(zhí)行代碼時(shí),事件循環(huán)最終會(huì)命中輪詢階段,等待傳入連接、請(qǐng)求等。但是,如果回調(diào)已計(jì)劃為 setImmediate(),并且輪詢階段變?yōu)榭臻e狀態(tài),則它將結(jié)束并繼續(xù)到檢查階段而不是等待輪詢事件。

setImmediate() 實(shí)際上是一個(gè)在事件循環(huán)的單獨(dú)階段運(yùn)行的特殊計(jì)時(shí)器。它使用一個(gè) libuv API 來(lái)安排回調(diào)在 poll 階段完成后執(zhí)行。

close callbacks

如果套接字或處理函數(shù)突然關(guān)閉(例如 socket.destroy()),則'close' 事件將在這個(gè)階段發(fā)出。否則它將通過(guò) process.nextTick() 發(fā)出。

setImmediate() 對(duì)比 setTimeout()

setImmediate() 和 setTimeout() 很類似,但何時(shí)調(diào)用行為完全不同。

setImmediate() 設(shè)計(jì)為在當(dāng)前 輪詢 階段完成后執(zhí)行腳本。

setTimeout() 計(jì)劃在毫秒的最小閾值經(jīng)過(guò)后運(yùn)行的腳本。

執(zhí)行計(jì)時(shí)器的順序?qū)⒏鶕?jù)調(diào)用它們的上下文而異,如果二者都從主模塊內(nèi)調(diào)用,則計(jì)時(shí)將受進(jìn)程性能的約束,兩個(gè)計(jì)時(shí)器的順序是非確定性的。

// timeout_vs_immediate.js

setTimeout(() => {

console.log('timeout');

}, 0);

setImmediate(() => {

console.log('immediate');

});

$ node timeout_vs_immediate.js

timeout

immediate

$ node timeout_vs_immediate.js

immediate

timeout

但是,如果你把這兩個(gè)函數(shù)放入一個(gè) I/O 循環(huán)內(nèi)調(diào)用,setImmediate 總是被優(yōu)先調(diào)用:

// timeout_vs_immediate.js

const fs = require('fs');

fs.readFile(__filename, () => {

setTimeout(() => {

console.log('timeout');

}, 0);

setImmediate(() => {

console.log('immediate');

});

});

$ node timeout_vs_immediate.js

immediate

timeout

$ node timeout_vs_immediate.js

immediate

timeout

使用 setImmediate() 超過(guò) setTimeout() 的主要優(yōu)點(diǎn)是 setImmediate() 在任何計(jì)時(shí)器(如果在 I/O 周期內(nèi))都將始終執(zhí)行,而不依賴于存在多少個(gè)計(jì)時(shí)器。

process.nextTick()

process.nextTick() 在技術(shù)上不是事件循環(huán)的一部分,無(wú)論事件循環(huán)的當(dāng)前階段如何,都將在當(dāng)前操作完成后處理 nextTickQueue。這里的一個(gè)操作被視作為一個(gè)從 C++ 底層處理開始過(guò)渡,并且處理需要執(zhí)行的 JavaScript 代碼。

回顧我們的關(guān)系圖,任何時(shí)候在給定的階段中調(diào)用 process.nextTick(),所有傳遞到 process.nextTick() 的回調(diào)將在事件循環(huán)繼續(xù)之前得到解決。這可能會(huì)造成一些糟糕的情況, 因?yàn)樗试S您通過(guò)進(jìn)行遞歸 process.nextTick() 來(lái)“餓死”您的 I/O 調(diào)用,阻止事件循環(huán)到達(dá) 輪詢 階段。

一個(gè)題目

// test.js

process.nextTick(function() {

console.log('next tick');

});

setTimeout(function() {

console.log('settimeout');

});

(async function() {

console.log('async promise');

})();

setImmediate(function() {

console.log('setimmediate');

});

$ node test.js

async promise

next tick

settimeout

setimmediate

沒有await,async那句其實(shí)是同步執(zhí)行的,故而第一句輸出。

next tick 在任何事件循環(huán)階段繼續(xù)之前得到解決,故而第二句

setTimeout 在主線程中與 setImmediate 的執(zhí)行順序是非確定性的

// test.js

setTimeout(function () {

process.nextTick(function() {

console.log('next tick');

});

setTimeout(function() {

console.log('settimeout');

});

(async function() {

console.log('async promise');

})();

setImmediate(function() {

console.log('setimmediate');

});

})

$ node test.js

async promise

next tick

setimmediate

settimeout

setimmediate 與 settimeout 放入一個(gè) I/O 循環(huán)內(nèi)調(diào)用,則 setImmediate 總是被優(yōu)先調(diào)用

node >= 11 ?

setTimeout(()=>{

console.log('timer1')

setImmediate(function () { console.log('immd 1'); })

Promise.resolve().then(function() {

console.log('promise1')

})

}, 0)

setTimeout(()=>{

console.log('timer2')

setImmediate(function () { console.log('immd 2'); })

Promise.resolve().then(function() {

console.log('promise2')

})

}, 0)

在 node 11 及以上版本打印得

timer1

promise1

timer2

promise2

immd 1

immd 2

在 node 版本為 8.11.2 打印

timer1

timer2

promise1

promise2

immd 1

immd 2

這是因?yàn)?< 11 得版本中

若第一個(gè)定時(shí)器任務(wù)出隊(duì)并執(zhí)行完,發(fā)現(xiàn)隊(duì)首的任務(wù)仍然是一個(gè)定時(shí)器,那么就將微任務(wù)暫時(shí)保存,直接去執(zhí)行新的定時(shí)器任務(wù),當(dāng)新的定時(shí)器任務(wù)執(zhí)行完后,再一一執(zhí)行中途產(chǎn)生的微任務(wù)。

nodejs 和 瀏覽器關(guān)于eventLoop的主要區(qū)別

兩者最主要的區(qū)別在于瀏覽器中的微任務(wù)是在每個(gè)相應(yīng)的宏任務(wù)中執(zhí)行的,而nodejs中的微任務(wù)是在不同階段之間執(zhí)行的。

總結(jié)

以上是生活随笔為你收集整理的node mysql 事件循环_NodeJs 的 Event loop 事件循环机制详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。