色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

剖析Node定時器

jf_78858299 ? 來源:前端大全 ? 作者:前端大全 ? 2023-04-21 14:19 ? 次閱讀

JavaScript 是單線程運行,異步操作特別重要。

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

Node 的異步語法比瀏覽器更復雜,因為它可以跟內核對話,不得不搞了一個專門的庫 libuv 做這件事。這個庫負責各種回調函數的執行時間,畢竟異步任務最后還是要回到主線程,一個個排隊執行。

圖片

為了協調異步任務,Node 居然提供了四個定時器,讓任務可以在指定的時間運行。

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

前兩個是語言的標準,后兩個是 Node 獨有的。它們的寫法差不多,作用也差不多,不太容易區別。

你能說出下面代碼的運行結果嗎?

// test.js

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

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

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

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

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

運行結果如下。

$ node test.js

5

3

4

1

2

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

一、同步任務和異步任務

首先,同步任務總是比異步任務更早執行。

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

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

二、本輪循環和次輪循環

異步任務可以分成兩種。

  • 追加在本輪循環的異步任務
  • 追加在次輪循環的異步任務

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

Node 規定,process.nextTick和Promise的回調函數,追加在本輪循環,即同步任務一旦執行完成,就開始執行它們。而setTimeout、setInterval、setImmediate的回調函數,追加在次輪循環。

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

// 下面兩行,次輪循環執行

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

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

// 下面兩行,本輪循環執行

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

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

三、process.nextTick()

process.nextTick這個名字有點誤導,它是在本輪循環執行的,而且是所有異步任務里面最快執行的。

圖片

Node 執行完所有同步任務,接下來就會執行process.nextTick的任務隊列。所以,下面這行代碼是第二個輸出結果。

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

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

四、微任務

根據語言規格,Promise對象的回調函數,會進入異步任務里面的”微任務”(microtask)隊列。

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

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

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

// 3

// 4

圖片

注意,只有前一個隊列全部清空以后,才會執行下一個隊列。

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的回調函數,執行都會早于Promise的。

至此,本輪循環的執行順序就講完了。

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

五、事件循環的概念

下面開始介紹次輪循環的執行順序,這就必須理解什么是事件循環(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.”

這段話很重要,需要仔細讀。它表達了三層意思。

首先,有些人以為,除了主線程,還存在一個單獨的事件循環線程。不是這樣的,只有一個主線程,事件循環是在主線程上完成的。

其次,Node 開始執行腳本時,會先進行事件循環的初始化,但是這時事件循環還沒有開始,會先完成下面的事情。

  • 同步任務
  • 發出異步請求
  • 規劃定時器生效的時間
  • 執行process.nextTick()等等

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

六、事件循環的六個階段

事件循環會無限次地執行,一輪又一輪。只有異步任務的回調函數隊列清空了,才會停止執行。

每一輪的事件循環,分成六個階段。這些階段會依次執行。

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

每個階段都有一個先進先出的回調函數隊列。只有一個階段的回調函數隊列清空了,該執行的回調函數都執行了,事件循環才會進入下一個階段。

圖片

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

(1)timers

這個是定時器階段,處理setTimeout()和setInterval()的回調函數。進入這個階段后,主線程會檢查一下當前時間,是否滿足定時器的條件。如果滿足就執行回調函數,否則就離開這個階段。

(2)I/O callbacks

除了以下操作的回調函數,其他的回調函數都在這個階段執行。

  • setTimeout()和setInterval()的回調函數
  • setImmediate()的回調函數
  • 用于關閉請求的回調函數,比如socket.on('close', ...)

(3)idle, prepare

該階段只供 libuv 內部調用,這里可以忽略。

(4)Poll

這個階段是輪詢時間,用于等待還未返回的 I/O 事件,比如服務器的回應、用戶移動鼠標等等。

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

(5)check

該階段執行setImmediate()的回調函數。

(6)close callbacks

該階段執行關閉請求的回調函數,比如socket.on('close', ...)。

七、事件循環的示例

下面是來自官方文檔的一個示例。

const fs = require('fs');

const timeoutScheduled = Date.now();

// 異步任務一:100ms 后執行的定時器

setTimeout(() => {

const delay = Date.now() - timeoutScheduled;

console.log(${delay}ms);

}, 100);

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

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

const startCallback = Date.now();

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

// 什么也不做

}

});

上面代碼有兩個異步任務,一個是 100ms 后執行的定時器,一個是至少需要 200ms 的文件讀取。請問運行結果是什么?

圖片

腳本進入第一輪事件循環以后,沒有到期的定時器,也沒有已經可以執行的 I/O 回調函數,所以會進入 Poll 階段,等待內核返回文件讀取的結果。由于讀取小文件一般不會超過 100ms,所以在定時器到期之前,Poll 階段就會得到結果,因此就會繼續往下執行。

第二輪事件循環,依然沒有到期的定時器,但是已經有了可以執行的 I/O 回調函數,所以會進入 I/O callbacks 階段,執行fs.readFile的回調函數。這個回調函數需要 200ms,也就是說,在它執行到一半的時候,100ms 的定時器就會到期。但是,必須等到這個回調函數執行完,才會離開這個階段。

第三輪事件循環,已經有了到期的定時器,所以會在 timers 階段執行定時器。最后輸出結果大概是200多毫秒。

八、setTimeout 和 setImmediate

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

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

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

上面代碼應該先輸出1,再輸出2,但是實際執行的時候,結果卻是不確定,有時還會先輸出2,再輸出1。

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

實際執行的時候,進入事件循環以后,有可能到了1毫秒,也可能還沒到1毫秒,取決于系統當時的狀況。如果沒到1毫秒,那么 timers 階段就會跳過,進入 check 階段,先執行setImmediate的回調函數。

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

const fs = require('fs');

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

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

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

});

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

九、參考鏈接

  • 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

(完)

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 定時器
    +關注

    關注

    23

    文章

    3246

    瀏覽量

    114720
  • javascript
    +關注

    關注

    0

    文章

    516

    瀏覽量

    53851
  • node
    +關注

    關注

    0

    文章

    23

    瀏覽量

    5934
收藏 人收藏

    評論

    相關推薦

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

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

    555定時器

    555定時器555定時器555定時器555定時器555定時器555定時器555
    發表于 11-10 17:25 ?52次下載

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

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

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

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

    STM32定時器-基本定時器

    目錄定時器分類基本定時器功能框圖講解基本定時器功能時鐘源計數時鐘計數自動重裝載寄存
    發表于 11-23 18:21 ?31次下載
    STM32<b class='flag-5'>定時器</b>-基本<b class='flag-5'>定時器</b>

    基于硬件定時器的軟件定時器

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

    STM32——高級定時器、通用定時器、基本定時器的區別

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

    STM32定時器學習---基本定時器

    STM32F1系列的產品,除了互聯網產品外,工作8個,3種定時器,其中一種就是基本定時器。那么STM32單片機的基本定時器如何操作以及編程呢?下面我們就來詳細的了解一下STM32F1系列的產品,除了
    發表于 12-02 14:06 ?28次下載
    STM32<b class='flag-5'>定時器</b>學習---基本<b class='flag-5'>定時器</b>

    SysTick 定時器

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

    31章-定時器

    基本定時器TIMSTM32F1 系列中,除了互聯型的產品,共有8 個定時器,分為基本定時器,通用定時器和高級定時器。基本
    發表于 01-17 09:39 ?3次下載
    31章-<b class='flag-5'>定時器</b>

    基礎定時器實驗

    STM32內部共有8個定時器,其中Timer1和Timer8屬于高級定時器,Timer2~Timer5屬于通用定時器,8個定時器的資源獨立,互不影響。
    的頭像 發表于 03-01 15:59 ?1195次閱讀
    基礎<b class='flag-5'>定時器</b>實驗

    剖析STM32-定時器1

    定時器作為微控制不可缺少的外設,在STM32中也是如此。相信不少初學者學到定時器的時候對STM32的學習熱情就大打折扣甚至想要放棄了,因為這一部分知識確實比較復雜。但是,如果你在之前對GPIO、串口通信、外部中斷的學習中把這些
    的頭像 發表于 04-21 15:14 ?1960次閱讀
    <b class='flag-5'>剖析</b>STM32-<b class='flag-5'>定時器</b>1

    剖析STM32-定時器2

    定時器作為微控制不可缺少的外設,在STM32中也是如此。相信不少初學者學到定時器的時候對STM32的學習熱情就大打折扣甚至想要放棄了,因為這一部分知識確實比較復雜。但是,如果你在之前對GPIO、串口通信、外部中斷的學習中把這些
    的頭像 發表于 04-21 15:14 ?1332次閱讀

    剖析STM32-定時器3

    定時器作為微控制不可缺少的外設,在STM32中也是如此。相信不少初學者學到定時器的時候對STM32的學習熱情就大打折扣甚至想要放棄了,因為這一部分知識確實比較復雜。但是,如果你在之前對GPIO、串口通信、外部中斷的學習中把這些
    的頭像 發表于 04-21 15:14 ?2306次閱讀
    <b class='flag-5'>剖析</b>STM32-<b class='flag-5'>定時器</b>3

    什么是軟件定時器?軟件定時器的實現原理

    軟件定時器是用程序模擬出來的定時器,可以由一個硬件定時器模擬出成千上萬個軟件定時器,這樣程序在需要使用較多定時器的時候就不會受限于硬件資源的
    的頭像 發表于 05-23 17:05 ?2778次閱讀
    主站蜘蛛池模板: 黄色三级视频网站| 九九热在线视频观看这里只有精品| 久久久久亚洲精品影视| 日韩精品a在线视频| 在线va无卡无码高清| 国产成人精品三级在线| 露露的性战k8经典| 亚洲薄码区| 高h 大尺度纯肉 np快穿| 么公一夜要了我一八次视频HD| 四虎影院2022| xxnxx美女| 老师湿乎乎两半嫩| 亚洲欧美综合中文| 国产精品成人不卡在线观看| 欧美18videosex| 在线视频a| 精品国产人妻国语| 我的好妈妈8高清在线观看WWW| 99久久热视频只有精品| 久久亚洲这里只有精品18| 亚洲欧美一区二区三区四区| 国产精品免费大片| 乳液全集电影在线观看| 欧美特黄三级成人| 色欲AV蜜臀AV在线观看麻豆| 夫妻日本换H视频| 美女打开双腿扒开屁股男生| 一本到道免费线观看| 国产无遮挡色视频免费观看性色| 色久悠悠无码偷拍自怕| music radio在线收听| 男男被强bl高h文| 最新国产麻豆精品| 久久视频精品38在线播放| 亚洲色图在线播放| 国产专区青青在线视频| 午夜神器老司机高清无码| 国产成人精品综合在线| 色多多污网站在线观看| 成人精品视频99在线观看免费|