亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Node.js中的定時器是什么

發布時間:2020-12-04 14:01:45 來源:億速云 閱讀:148 作者:小新 欄目:web開發

小編給大家分享一下Node.js中的定時器是什么,相信大部分人都還不怎么了解,因此分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后大有收獲,下面讓我們一起去了解一下吧!

timer 用于安排函數在未來某個時間點被調用,Node.js 中的定時器函數實現了與 Web 瀏覽器提供的定時器 API 類似的 API,但是使用了事件循環實現,Node.js 中有四個相關的方法

  • setTimeout(callback, delay[, ...args])

  • setInterval(callback[, ...args])

  • setImmediate(callback[, ...args])

  • process.nextTick(callback[, ...args])

前兩個含義和 web 上的是一致的,后兩個是 Node.js 獨有的,效果看起來就是 setTimeout(callback, 0),在 Node.js 編程中使用的最多

Node.js 不保證回調被觸發的確切時間,也不保證它們的順序,回調會在盡可能接近指定的時間被調用。setTimeout 當 delay 大于 2147483647 或小于 1 時,則 delay 將會被設置為 1, 非整數的 delay 會被截斷為整數

奇怪的執行順序

看一個示例,用幾種方法分別異步打印一個數字

setImmediate(console.log, 1);
setTimeout(console.log, 1, 2);
Promise.resolve(3).then(console.log);
process.nextTick(console.log, 4);
console.log(5);

會打印 5 4 3 2 1 或者 5 4 3 1 2

同步 & 異步

第五行是同步執行,其它都是異步的

setImmediate(console.log, 1);
setTimeout(console.log, 1, 2);
Promise.resolve(3).then(console.log);
process.nextTick(console.log, 4);
/****************** 同步任務和異步任務的分割線 ********************/
console.log(5);

所以先打印 5,這個很好理解,剩下的都是異步操作,Node.js 按照什么順序執行呢?

event loop

Node.js 啟動后會初始化事件輪詢,過程中可能處理異步調用、定時器調度和 process.nextTick(),然后開始處理event loop。官網中有這樣一張圖用來介紹 event loop 操作順序

┌───────────────────────────┐
┌─>│           timers          │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │     pending callbacks     │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
│  │       idle, prepare       │
│  └─────────────┬─────────────┘      ┌───────────────┐
│  ┌─────────────┴─────────────┐      │   incoming:   │
│  │           poll            │<─────┤  connections, │
│  └─────────────┬─────────────┘      │   data, etc.  │
│  ┌─────────────┴─────────────┐      └───────────────┘
│  │           check           │
│  └─────────────┬─────────────┘
│  ┌─────────────┴─────────────┐
└──┤      close callbacks      │
   └───────────────────────────┘

event loop 的每個階段都有一個任務隊列,當 event loop 進入給定的階段時,將執行該階段的任務隊列,直到隊列清空或執行的回調達到系統上限后,才會轉入下一個階段,當所有階段被順序執行一次后,稱 event loop 完成了一個 tick

異步操作都被放到了下一個 event loop tick 中,process.nextTick 在進入下一次 event loop tick 之前執行,所以肯定在其它異步操作之前

setImmediate(console.log, 1);
setTimeout(console.log, 1, 2);
Promise.resolve(3).then(console.log);
/****************** 下次 event loop tick 分割線 ********************/
process.nextTick(console.log, 4);
/****************** 同步任務和異步任務的分割線 ********************/
console.log(5);

各個階段主要任務

  • timers:執行 setTimeout、setInterval 回調

  • pending callbacks:執行 I/O(文件、網絡等) 回調

  • idle, prepare:僅供系統內部調用

  • poll:獲取新的 I/O 事件,執行相關回調,在適當條件下把阻塞 node

  • check:setImmediate 回調在此階段執行

  • close callbacks:執行 socket 等的 close 事件回調

日常開發中絕大部分異步任務都是在 timers、poll、check 階段處理的

timers

Node.js 會在 timers 階段檢查是否有過期的 timer,如果存在則把回調放到 timer 隊列中等待執行,Node.js 使用單線程,受限于主線程空閑情況和機器其它進程影響,并不能保證 timer 按照精確時間執行
定時器主要有兩種

  • Immediate

  • Timeout

Immediate 類型的計時器回調會在 check 階段被調用,Timeout 計時器會在設定的時間過期后盡快的調用回調,但

setTimeout(() => {
  console.log('timeout');
}, 0);

setImmediate(() => {
  console.log('immediate');
});

多次執行會發現打印的順序不一樣

poll

poll 階段主要有兩個任務

  • 計算應該阻塞和輪詢 I/O 的時間

  • 然后,處理 poll 隊列里的事件

當event loop進入 poll 階段且沒有被調度的計時器時

  • 如果 poll 隊列不是空的 ,event loop 將循環訪問回調隊列并同步執行,直到隊列已用盡或者達到了系統或達到最大回調數
  • 如果 poll 隊列是空的
    • 如果有 setImmediate() 任務,event loop 會在結束 poll 階段后進入 check 階段
    • 如果沒有 setImmediate()任務,event loop 阻塞在 poll 階段等待回調被添加到隊列中,然后立即執行

一旦 poll 隊列為空,event loop 將檢查 timer 隊列是否為空,如果非空則進入下一輪 event loop

上面提到了如果在不同的 I/O 里,不能確定 setTimeout 和 setImmediate 的執行順序,但如果 setTimeout 和 setImmediate 在一個 I/O 回調里,肯定是 setImmediate 先執行,因為在 poll 階段檢查到有 setImmediate() 任務,event loop 直接進入 check 階段執行 setImmediate 回調

const fs = require('fs');
fs.readFile(__filename, () => {
  setTimeout(() => {
    console.log('timeout');
  }, 0);
  setImmediate(() => {
    console.log('immediate');
  });
});

check

在該階段執行 setImmediate 回調

為什么 Promise.then 比 setTimeout 早一些

前端同學肯定都聽說過 micoTask 和 macroTask,Promise.then 屬于 microTask,在瀏覽器環境下 microTask 任務會在每個 macroTask 執行最末端調用

在 Node.js 環境下 microTask 會在每個階段完成之間調用,也就是每個階段執行最后都會執行一下 microTask 隊列

setImmediate(console.log, 1);
setTimeout(console.log, 1, 2);
/****************** microTask 分割線 ********************/
Promise.resolve(3).then(console.log); // microTask 分割線
/****************** 下次 event loop tick 分割線 ********************/
process.nextTick(console.log, 4);
/****************** 同步任務和異步任務的分割線 ********************/
console.log(5);

setImmediate VS process.nextTick

setImmediate 聽起來是立即執行,process.nextTick 聽起來是下一個時鐘執行,為什么效果是反過來的?這就要從那段不堪回首的歷史講起

最開始的時候只有 process.nextTick 方法,沒有 setImmediate 方法,通過上面的分析可以看出來任何時候調用 process.nextTick(),nextTick 會在 event loop 之前執行,直到 nextTick 隊列被清空才會進入到下一 event loop,如果出現 process.nextTick 的遞歸調用程序沒有被正確結束,那么 IO 的回調將沒有機會被執行

const fs = require('fs');

fs.readFile('a.txt', (err, data) => {
	console.log('read file task done!');
});

let i = 0;
function test(){
	if(i++ < 999999) {
  	console.log(`process.nextTick ${i}`);
    process.nextTick(test);
  }
}
test();

執行程序將返回

nextTick 1
nextTick 2
...
...
nextTick 999999
read file task done!

于是乎需要一個不這么 bug 的調用,setImmediate 方法出現了,比較令人費解的是在 process.nextTick 起錯名字的情況下,setImmediate 也用了一個錯誤的名字以示區分。。。

那么是不是編程中應該杜絕使用  process.nextTick 呢?官方推薦大部分時候應該使用 setImmediate,同時對 process.nextTick 的最大調用堆棧做了限制,但 process.nextTick 的調用機制確實也能為我們解決一些棘手的問題

  • 允許用戶在 even tloop 開始之前 處理異常、執行清理任務

  • 允許回調在調用棧 unwind 之后,下次 event loop 開始之前執行

一個類繼承了 EventEmitter,而且想在實例化的時候觸發一個事件

const EventEmitter = require('events');
const util = require('util');

function MyEmitter() {
  EventEmitter.call(this);
  this.emit('event');
}
util.inherits(MyEmitter, EventEmitter);

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});

在構造函數執行 this.emit('event') 會導致事件觸發比事件回調函數綁定早,使用 process.nextTick 可以輕松實現預期效果

const EventEmitter = require('events');
const util = require('util');

function MyEmitter() {
  EventEmitter.call(this);

  // use nextTick to emit the event once a handler is assigned
  process.nextTick(() => {
    this.emit('event');
  });
}
util.inherits(MyEmitter, EventEmitter);

const myEmitter = new MyEmitter();
myEmitter.on('event', () => {
  console.log('an event occurred!');
});

以上是“Node.js中的定時器是什么”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

元谋县| 甘孜县| 康定县| 突泉县| 隆德县| 平陆县| 兰考县| 武宣县| 商南县| 龙里县| 绥江县| 林芝县| 双流县| 清丰县| 荥经县| 沙洋县| 南京市| 康保县| 元谋县| 蓬莱市| 邢台县| 大渡口区| 扬州市| 武邑县| 宁陵县| 闻喜县| 汶上县| 莎车县| 贵溪市| 始兴县| 西畴县| 曲阳县| 土默特右旗| 台前县| 九龙坡区| 青铜峡市| 怀仁县| 隆林| 林芝县| 盈江县| 恩平市|