哈哈哈哈哈操欧洲电影,久草网在线,亚洲久久熟女熟妇视频,麻豆精品色,久久福利在线视频,日韩中文字幕的,淫乱毛视频一区,亚洲成人一二三,中文人妻日韩精品电影

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

剖析Node定時(shí)器

jf_78858299 ? 來源:前端大全 ? 作者:前端大全 ? 2023-04-21 14:19 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

JavaScript 是單線程運(yùn)行,異步操作特別重要。

只要用到引擎之外的功能,就需要跟外部交互,從而形成異步操作。由于異步操作實(shí)在太多,JavaScript 不得不提供很多異步語法。這就好比,有些人老是受打擊, 他的抗打擊能力必須變得很強(qiáng),否則他就完蛋了。

Node 的異步語法比瀏覽器更復(fù)雜,因?yàn)樗梢愿鷥?nèi)核對話,不得不搞了一個(gè)專門的庫 libuv 做這件事。這個(gè)庫負(fù)責(zé)各種回調(diào)函數(shù)的執(zhí)行時(shí)間,畢竟異步任務(wù)最后還是要回到主線程,一個(gè)個(gè)排隊(duì)執(zhí)行。

圖片

為了協(xié)調(diào)異步任務(wù),Node 居然提供了四個(gè)定時(shí)器,讓任務(wù)可以在指定的時(shí)間運(yùn)行。

  • setTimeout()
  • setInterval()
  • setImmediate()
  • process.nextTick()

前兩個(gè)是語言的標(biāo)準(zhǔn),后兩個(gè)是 Node 獨(dú)有的。它們的寫法差不多,作用也差不多,不太容易區(qū)別。

你能說出下面代碼的運(yùn)行結(jié)果嗎?

// test.js

setTimeout(() => console.log(1));

setImmediate(() => console.log(2));

process.nextTick(() => console.log(3));

Promise.resolve().then(() => console.log(4));

(() => console.log(5))();

運(yùn)行結(jié)果如下。

$ node test.js

5

3

4

1

2

如果你能一口說對,可能就不需要再看下去了。本文詳細(xì)解釋,Node 怎么處理各種定時(shí)器,或者更廣義地說,libuv 庫怎么安排異步任務(wù)在主線程上執(zhí)行。

一、同步任務(wù)和異步任務(wù)

首先,同步任務(wù)總是比異步任務(wù)更早執(zhí)行。

前面的那段代碼,只有最后一行是同步任務(wù),因此最早執(zhí)行。

(() => console.log(5))();

二、本輪循環(huán)和次輪循環(huán)

異步任務(wù)可以分成兩種。

  • 追加在本輪循環(huán)的異步任務(wù)
  • 追加在次輪循環(huán)的異步任務(wù)

所謂”循環(huán)”,指的是事件循環(huán)(event loop)。這是 JavaScript 引擎處理異步任務(wù)的方式,后文會詳細(xì)解釋。這里只要理解,本輪循環(huán)一定早于次輪循環(huán)執(zhí)行即可。

Node 規(guī)定,process.nextTick和Promise的回調(diào)函數(shù),追加在本輪循環(huán),即同步任務(wù)一旦執(zhí)行完成,就開始執(zhí)行它們。而setTimeout、setInterval、setImmediate的回調(diào)函數(shù),追加在次輪循環(huán)。

這就是說,文首那段代碼的第三行和第四行,一定比第一行和第二行更早執(zhí)行。

// 下面兩行,次輪循環(huán)執(zhí)行

setTimeout(() => console.log(1));

setImmediate(() => console.log(2));

// 下面兩行,本輪循環(huán)執(zhí)行

process.nextTick(() => console.log(3));

Promise.resolve().then(() => console.log(4));

三、process.nextTick()

process.nextTick這個(gè)名字有點(diǎn)誤導(dǎo),它是在本輪循環(huán)執(zhí)行的,而且是所有異步任務(wù)里面最快執(zhí)行的。

圖片

Node 執(zhí)行完所有同步任務(wù),接下來就會執(zhí)行process.nextTick的任務(wù)隊(duì)列。所以,下面這行代碼是第二個(gè)輸出結(jié)果。

process.nextTick(() => console.log(3));

基本上,如果你希望異步任務(wù)盡可能快地執(zhí)行,那就使用process.nextTick。

四、微任務(wù)

根據(jù)語言規(guī)格,Promise對象的回調(diào)函數(shù),會進(jìn)入異步任務(wù)里面的”微任務(wù)”(microtask)隊(duì)列。

微任務(wù)隊(duì)列追加在process.nextTick隊(duì)列的后面,也屬于本輪循環(huán)。所以,下面的代碼總是先輸出3,再輸出4。

process.nextTick(() => console.log(3));

Promise.resolve().then(() => console.log(4));

// 3

// 4

圖片

注意,只有前一個(gè)隊(duì)列全部清空以后,才會執(zhí)行下一個(gè)隊(duì)列。

process.nextTick(() => console.log(1));

Promise.resolve().then(() => console.log(2));

process.nextTick(() => console.log(3));

Promise.resolve().then(() => console.log(4));

// 1

// 3

// 2

// 4

上面代碼中,全部process.nextTick的回調(diào)函數(shù),執(zhí)行都會早于Promise的。

至此,本輪循環(huán)的執(zhí)行順序就講完了。

  1. 同步任務(wù)
  2. process.nextTick()
  3. 微任務(wù)

五、事件循環(huán)的概念

下面開始介紹次輪循環(huán)的執(zhí)行順序,這就必須理解什么是事件循環(huán)(event loop)了。

Node 的官方文檔是這樣介紹的。

“When Node.js starts, it initializes the event loop, processes the provided input script which may make async API calls, schedule timers, or call process.nextTick(), then begins processing the event loop.”

這段話很重要,需要仔細(xì)讀。它表達(dá)了三層意思。

首先,有些人以為,除了主線程,還存在一個(gè)單獨(dú)的事件循環(huán)線程。不是這樣的,只有一個(gè)主線程,事件循環(huán)是在主線程上完成的。

其次,Node 開始執(zhí)行腳本時(shí),會先進(jìn)行事件循環(huán)的初始化,但是這時(shí)事件循環(huán)還沒有開始,會先完成下面的事情。

  • 同步任務(wù)
  • 發(fā)出異步請求
  • 規(guī)劃定時(shí)器生效的時(shí)間
  • 執(zhí)行process.nextTick()等等

最后,上面這些事情都干完了,事件循環(huán)就正式開始了。

六、事件循環(huán)的六個(gè)階段

事件循環(huán)會無限次地執(zhí)行,一輪又一輪。只有異步任務(wù)的回調(diào)函數(shù)隊(duì)列清空了,才會停止執(zhí)行。

每一輪的事件循環(huán),分成六個(gè)階段。這些階段會依次執(zhí)行。

  1. timers
  2. I/O callbacks
  3. idle, prepare
  4. poll
  5. check
  6. close callbacks

每個(gè)階段都有一個(gè)先進(jìn)先出的回調(diào)函數(shù)隊(duì)列。只有一個(gè)階段的回調(diào)函數(shù)隊(duì)列清空了,該執(zhí)行的回調(diào)函數(shù)都執(zhí)行了,事件循環(huán)才會進(jìn)入下一個(gè)階段。

圖片

下面簡單介紹一下每個(gè)階段的含義,詳細(xì)介紹可以看官方文檔,也可以參考 libuv 的源碼解讀。

(1)timers

這個(gè)是定時(shí)器階段,處理setTimeout()和setInterval()的回調(diào)函數(shù)。進(jìn)入這個(gè)階段后,主線程會檢查一下當(dāng)前時(shí)間,是否滿足定時(shí)器的條件。如果滿足就執(zhí)行回調(diào)函數(shù),否則就離開這個(gè)階段。

(2)I/O callbacks

除了以下操作的回調(diào)函數(shù),其他的回調(diào)函數(shù)都在這個(gè)階段執(zhí)行。

  • setTimeout()和setInterval()的回調(diào)函數(shù)
  • setImmediate()的回調(diào)函數(shù)
  • 用于關(guān)閉請求的回調(diào)函數(shù),比如socket.on('close', ...)

(3)idle, prepare

該階段只供 libuv 內(nèi)部調(diào)用,這里可以忽略。

(4)Poll

這個(gè)階段是輪詢時(shí)間,用于等待還未返回的 I/O 事件,比如服務(wù)器的回應(yīng)、用戶移動(dòng)鼠標(biāo)等等。

這個(gè)階段的時(shí)間會比較長。如果沒有其他異步任務(wù)要處理(比如到期的定時(shí)器),會一直停留在這個(gè)階段,等待 I/O 請求返回結(jié)果。

(5)check

該階段執(zhí)行setImmediate()的回調(diào)函數(shù)。

(6)close callbacks

該階段執(zhí)行關(guān)閉請求的回調(diào)函數(shù),比如socket.on('close', ...)。

七、事件循環(huán)的示例

下面是來自官方文檔的一個(gè)示例。

const fs = require('fs');

const timeoutScheduled = Date.now();

// 異步任務(wù)一:100ms 后執(zhí)行的定時(shí)器

setTimeout(() => {

const delay = Date.now() - timeoutScheduled;

console.log(${delay}ms);

}, 100);

// 異步任務(wù)二:至少需要 200ms 的文件讀取

fs.readFile('test.js', () => {

const startCallback = Date.now();

while (Date.now() - startCallback < 200) {

// 什么也不做

}

});

上面代碼有兩個(gè)異步任務(wù),一個(gè)是 100ms 后執(zhí)行的定時(shí)器,一個(gè)是至少需要 200ms 的文件讀取。請問運(yùn)行結(jié)果是什么?

圖片

腳本進(jìn)入第一輪事件循環(huán)以后,沒有到期的定時(shí)器,也沒有已經(jīng)可以執(zhí)行的 I/O 回調(diào)函數(shù),所以會進(jìn)入 Poll 階段,等待內(nèi)核返回文件讀取的結(jié)果。由于讀取小文件一般不會超過 100ms,所以在定時(shí)器到期之前,Poll 階段就會得到結(jié)果,因此就會繼續(xù)往下執(zhí)行。

第二輪事件循環(huán),依然沒有到期的定時(shí)器,但是已經(jīng)有了可以執(zhí)行的 I/O 回調(diào)函數(shù),所以會進(jìn)入 I/O callbacks 階段,執(zhí)行fs.readFile的回調(diào)函數(shù)。這個(gè)回調(diào)函數(shù)需要 200ms,也就是說,在它執(zhí)行到一半的時(shí)候,100ms 的定時(shí)器就會到期。但是,必須等到這個(gè)回調(diào)函數(shù)執(zhí)行完,才會離開這個(gè)階段。

第三輪事件循環(huán),已經(jīng)有了到期的定時(shí)器,所以會在 timers 階段執(zhí)行定時(shí)器。最后輸出結(jié)果大概是200多毫秒。

八、setTimeout 和 setImmediate

由于setTimeout在 timers 階段執(zhí)行,而setImmediate在 check 階段執(zhí)行。所以,setTimeout會早于setImmediate完成。

setTimeout(() => console.log(1));

setImmediate(() => console.log(2));

上面代碼應(yīng)該先輸出1,再輸出2,但是實(shí)際執(zhí)行的時(shí)候,結(jié)果卻是不確定,有時(shí)還會先輸出2,再輸出1。

這是因?yàn)閟etTimeout的第二個(gè)參數(shù)默認(rèn)為0。但是實(shí)際上,Node 做不到0毫秒,最少也需要1毫秒,根據(jù)官方文檔,第二個(gè)參數(shù)的取值范圍在1毫秒到2147483647毫秒之間。也就是說,setTimeout(f, 0)等同于setTimeout(f, 1)。

實(shí)際執(zhí)行的時(shí)候,進(jìn)入事件循環(huán)以后,有可能到了1毫秒,也可能還沒到1毫秒,取決于系統(tǒng)當(dāng)時(shí)的狀況。如果沒到1毫秒,那么 timers 階段就會跳過,進(jìn)入 check 階段,先執(zhí)行setImmediate的回調(diào)函數(shù)。

但是,下面的代碼一定是先輸出2,再輸出1。

const fs = require('fs');

fs.readFile('test.js', () => {

setTimeout(() => console.log(1));

setImmediate(() => console.log(2));

});

上面代碼會先進(jìn)入 I/O callbacks 階段,然后是 check 階段,最后才是 timers 階段。因此,setImmediate才會早于setTimeout執(zhí)行。

九、參考鏈接

  • The Node.js Event Loop, Timers, and process.nextTick(), by Node.js
  • Handling IO?–?NodeJS Event Loop, by Deepal Jayasekara
  • setImmediate() vs nextTick() vs setTimeout(fn,0) – in depth explanation, by Paul Shan
  • Node.js event loop workflow & lifecycle in low level, by Paul Shan

(完)

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報(bào)投訴
  • 定時(shí)器
    +關(guān)注

    關(guān)注

    23

    文章

    3370

    瀏覽量

    124369
  • javascript
    +關(guān)注

    關(guān)注

    0

    文章

    526

    瀏覽量

    56499
  • node
    +關(guān)注

    關(guān)注

    0

    文章

    30

    瀏覽量

    6419
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評論

    相關(guān)推薦
    熱點(diǎn)推薦

    STM32定時(shí)器(二)定時(shí)器中斷

    常規(guī)定時(shí)器:基本定時(shí)器TIM6&TIM7)、通用定時(shí)器(TIM2~TIM5,TIM9~TIM14)、高級定時(shí)器(TIM1&TIM8)
    的頭像 發(fā)表于 07-21 14:54 ?5544次閱讀
    STM32<b class='flag-5'>定時(shí)器</b>(二)<b class='flag-5'>定時(shí)器</b>中斷

    555定時(shí)器

    555定時(shí)器555定時(shí)器555定時(shí)器555定時(shí)器555定時(shí)器555定時(shí)器555
    發(fā)表于 11-10 17:25 ?55次下載

    剖析Zynq-7000系列全局定時(shí)器(GT)

    每個(gè) Cortex-A9 處理都有自己的私有 32 位定時(shí)器和 32 位看門狗定時(shí)器,兩個(gè)處理共享一個(gè)全局 64 位定時(shí)器,這些
    的頭像 發(fā)表于 06-16 16:49 ?4323次閱讀
    <b class='flag-5'>剖析</b>Zynq-7000系列全局<b class='flag-5'>定時(shí)器</b>(GT)

    定時(shí)器電路圖工作原理(聲光提示定時(shí)器電路/555定時(shí)器電路/相片曝光定時(shí)器電路)

    定時(shí)器根據(jù)其輸入條件導(dǎo)致完成動(dòng)作的不同可分為接通延時(shí)型定時(shí)器、斷開延時(shí)型定時(shí)器、保持型接通延時(shí)定時(shí)器、脈沖型定時(shí)器和擴(kuò)張型脈沖
    發(fā)表于 11-05 16:07 ?1.9w次閱讀
    <b class='flag-5'>定時(shí)器</b>電路圖工作原理(聲光提示<b class='flag-5'>定時(shí)器</b>電路/555<b class='flag-5'>定時(shí)器</b>電路/相片曝光<b class='flag-5'>定時(shí)器</b>電路)

    STM32定時(shí)器-基本定時(shí)器

    目錄定時(shí)器分類基本定時(shí)器功能框圖講解基本定時(shí)器功能時(shí)鐘源計(jì)數(shù)時(shí)鐘計(jì)數(shù)自動(dòng)重裝載寄存
    發(fā)表于 11-23 18:21 ?32次下載
    STM32<b class='flag-5'>定時(shí)器</b>-基本<b class='flag-5'>定時(shí)器</b>

    基于硬件定時(shí)器的軟件定時(shí)器

    概括硬件定時(shí)器很精確,軟件定時(shí)器無論如何都有延遲,主要用在不需要精確定時(shí)的地方,而且軟件定時(shí)比較浪費(fèi)單片機(jī)資源。梳理講到定時(shí)器,大家多多少少
    發(fā)表于 11-25 09:51 ?8次下載
    基于硬件<b class='flag-5'>定時(shí)器</b>的軟件<b class='flag-5'>定時(shí)器</b>

    STM32——高級定時(shí)器、通用定時(shí)器、基本定時(shí)器的區(qū)別

    STM32——高級定時(shí)器、通用定時(shí)器、基本定時(shí)器的區(qū)別
    發(fā)表于 11-26 15:21 ?110次下載
    STM32——高級<b class='flag-5'>定時(shí)器</b>、通用<b class='flag-5'>定時(shí)器</b>、基本<b class='flag-5'>定時(shí)器</b>的區(qū)別

    STM32-通用定時(shí)器-定時(shí)器中斷

    1STM32的定時(shí)器STM32F103ZET6一共有8個(gè)定時(shí)器,其中分別為:高級定時(shí)器(TIM1、TIM8);通用定時(shí)器(TIM2、TIM3、TIM4、TIM5);基本
    發(fā)表于 11-26 15:36 ?16次下載
    STM32-通用<b class='flag-5'>定時(shí)器</b>-<b class='flag-5'>定時(shí)器</b>中斷

    STM32定時(shí)器學(xué)習(xí)---基本定時(shí)器

    STM32F1系列的產(chǎn)品,除了互聯(lián)網(wǎng)產(chǎn)品外,工作8個(gè),3種定時(shí)器,其中一種就是基本定時(shí)器。那么STM32單片機(jī)的基本定時(shí)器如何操作以及編程呢?下面我們就來詳細(xì)的了解一下STM32F1系列的產(chǎn)品,除了
    發(fā)表于 12-02 14:06 ?28次下載
    STM32<b class='flag-5'>定時(shí)器</b>學(xué)習(xí)---基本<b class='flag-5'>定時(shí)器</b>

    SysTick 定時(shí)器

    11.1關(guān)于 SysTick 定時(shí)器SysTick定時(shí)器(又名系統(tǒng)滴答定時(shí)器)是存在于Cortex-M3的一個(gè)定時(shí)器,只要是ARM Cotex-M系列內(nèi)核的MCU都包含這個(gè)
    發(fā)表于 12-05 14:51 ?9次下載
    SysTick <b class='flag-5'>定時(shí)器</b>

    31章-定時(shí)器

    基本定時(shí)器TIMSTM32F1 系列中,除了互聯(lián)型的產(chǎn)品,共有8 個(gè)定時(shí)器,分為基本定時(shí)器,通用定時(shí)器和高級定時(shí)器?;?/div>
    發(fā)表于 01-17 09:39 ?3次下載
    31章-<b class='flag-5'>定時(shí)器</b>

    定時(shí)器開關(guān)怎么接線?

    定時(shí)器開關(guān):時(shí)間定時(shí)器開關(guān)、開關(guān)定時(shí)器、電源開關(guān)定時(shí)器,是控制用電器自動(dòng)定時(shí)開啟、關(guān)閉的電氣裝置。
    的頭像 發(fā)表于 02-24 15:38 ?1.6w次閱讀
    <b class='flag-5'>定時(shí)器</b>開關(guān)怎么接線?

    基礎(chǔ)定時(shí)器實(shí)驗(yàn)

    STM32內(nèi)部共有8個(gè)定時(shí)器,其中Timer1和Timer8屬于高級定時(shí)器,Timer2~Timer5屬于通用定時(shí)器,8個(gè)定時(shí)器的資源獨(dú)立,互不影響。
    的頭像 發(fā)表于 03-01 15:59 ?2845次閱讀
    基礎(chǔ)<b class='flag-5'>定時(shí)器</b>實(shí)驗(yàn)

    什么是軟件定時(shí)器?軟件定時(shí)器的實(shí)現(xiàn)原理

    軟件定時(shí)器是用程序模擬出來的定時(shí)器,可以由一個(gè)硬件定時(shí)器模擬出成千上萬個(gè)軟件定時(shí)器,這樣程序在需要使用較多定時(shí)器的時(shí)候就不會受限于硬件資源的
    的頭像 發(fā)表于 05-23 17:05 ?4439次閱讀

    定時(shí)器中斷是什么意思,定時(shí)器中斷的工作原理

    定時(shí)器中斷是由單片機(jī)中的定時(shí)器溢出而申請的中斷。51單片機(jī)中有兩個(gè)定時(shí)器T0和T1。STM32中共有11個(gè)定時(shí)器。
    的頭像 發(fā)表于 07-23 09:45 ?8417次閱讀
    杭锦旗| 安远县| 即墨市| 淮南市| 林口县| 千阳县| 原阳县| 镇沅| 化州市| 托克托县| 同仁县| 如东县| 施甸县| 磐安县| 彭州市| 稷山县| 烟台市| 宜君县| 灯塔市| 清新县| 富平县| 扎鲁特旗| 钦州市| 乌鲁木齐市| 班戈县| 柳河县| 英山县| 罗平县| 图木舒克市| 徐州市| 诏安县| 廉江市| 遵义市| 富宁县| 巍山| 武清区| 凌海市| 林口县| 龙井市| 新沂市| 桐庐县|