検索

ノードタイマーの詳細な分析

Feb 27, 2018 am 09:11 AM
nodeタイマー解析する

JavaScript は単一スレッドで実行され、非同期操作が特に重要です。この記事では主にノードタイマーに関する知識を紹介します。エンジン以外の機能を使用する限り、非同期操作を形成するには外部と対話する必要があります。非同期操作が非常に多いため、JavaScript は多くの非同期構文を提供する必要があります。

Node の非同期構文はブラウザの非同期構文よりも複雑です。これは、ノードがカーネルと通信できるためであり、これを行うには特別なライブラリ libuv を構築する必要があります。このライブラリは、さまざまなコールバック関数の実行時間を担当します。結局のところ、非同期タスクは最終的にメインスレッドに戻り、実行のために 1 つずつキューに入れられる必要があります。

非同期タスクを調整するために、Node は実際には指定された時間にタスクを実行できるように 4 つのタイマーを提供します。

  • settimeout()

  • setInterval()

  • setimmediate()

  • process.nexttick()

最初の2つは言語標準であり、最後の2つはノードに固有のものです。書き方も機能も似ているため、区別するのは簡単ではありません。

以下のコードを実行した結果を教えていただけますか?

// 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

すぐに理解できる場合は、これ以上読む必要はありません。この記事では、Node がさまざまなタイマーを処理する方法、またはより広範に、libuv ライブラリがメインスレッドで実行される非同期タスクを配置する方法について詳しく説明します。

1. 同期タスクと非同期タスク

まず、同期タスクは常に非同期タスクよりも先に実行されます。

前のコードでは、最後の行のみが同期タスクであるため、最も早く実行されます。

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

2. 現在のサイクルと二次サイクル

非同期タスクは 2 つのタイプに分類できます。

現在のサイクルに非同期タスクを追加します
2番目のサイクルに非同期タスクを追加します

いわゆる「ループ」とは、イベントループを指します。これは、JavaScript エンジンが非同期タスクを処理する方法です。これについては、後で詳しく説明します。ここで、このサイクルは 2 番目のサイクルよりも前に実行する必要があることを理解してください。

Node は、process.nextTick と Promise のコールバック関数がこのサイクルに追加されること、つまり、同期タスクが完了するとそれらが実行されることを規定します。 setTimeout、setInterval、setImmediate のコールバック関数が 2 サイクル目に追加されます。

これは、記事の冒頭のコードの 3 行目と 4 行目が、1 行目と 2 行目よりも早く実行される必要があることを意味します。

// 下面两行,次轮循环执行
setTimeout(() => console.log(1));
setImmediate(() => console.log(2));
// 下面两行,本轮循环执行
process.nextTick(() => console.log(3));
Promise.resolve().then(() => console.log(4));

3. process.nextTick()

process.nextTick という名前は少し誤解を招きますが、このサイクルで実行され、すべての非同期タスクの中で最も高速です。

ノードがすべての同期タスクを実行した後、process.nextTick のタスクキューを実行します。したがって、次のコード行は 2 番目の出力です。

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

基本的に、非同期タスクをできるだけ速く実行したい場合は、process.nextTick を使用します。

4. マイクロタスク

言語仕様に従って、Promise オブジェクトのコールバック関数は非同期タスクの「マイクロタスク」キューに入ります。

マイクロタスクキューは 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 よりも先に実行されます。

この時点で、このサイクルの実行シーケンスは終了します。

同步任务
process.nextTick()
微任务

5. イベント ループの概念

2 回目のループの実行シーケンスから始めましょう。これには、イベント ループとは何かを理解する必要があります。

まず、メインスレッドに加えて、別のイベントループスレッドがあると考える人もいます。そうではありません。メイン スレッドは 1 つだけあり、イベント ループはメイン スレッド上で完了します。

次に、Node がスクリプトの実行を開始すると、最初にイベント ループが初期化されますが、イベント ループはまだ開始されておらず、次のことが最初に完了します。

  • 同期タスク

  • 非同期リクエストを発行する

  • タイマーが有効になる時間を計画する

process.nextTick()などを実行する

上記の作業がすべて完了したら、最後に、イベントループは公式です。

6. 6 段階のイベント ループ

イベント ループはラウンドごとに無限に実行されます。非同期タスクのコールバック関数キューがクリアされた場合にのみ実行が停止します。

イベントループの各ラウンドは6つのステージに分かれています。これらのステージは順番に実行されます。

タイマー
I/Oコールバック
idle、prepare
poll
check
closeコールバック

各ステージには先入れ先出しコールバック関数キューがあります。あるステージのコールバック関数キューがクリアされ、実行されるべきコールバック関数がすべて実行された場合にのみ、イベント ループは次のステージに入ります。

下面简单介绍一下每个阶段的含义,详细介绍可以看官方文档,也可以参考 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 <p>上面代码有两个异步任务,一个是 100ms 后执行的定时器,一个是至少需要 200ms 的文件读取。请问运行结果是什么?</p><p><img src="/static/imghwm/default1.png" data-src="https://img.php.cn/upload/article/000/054/025/bb879731f400b02eba47769ebd3f65e1-4.jpg?x-oss-process=image/resize,p_40" class="lazy" title="" alt=""></p><p>脚本进入第一轮事件循环以后,没有到期的定时器,也没有已经可以执行的 I/O 回调函数,所以会进入 Poll 阶段,等待内核返回文件读取的结果。由于读取小文件一般不会超过 100ms,所以在定时器到期之前,Poll 阶段就会得到结果,因此就会继续往下执行。</p><p>第二轮事件循环,依然没有到期的定时器,但是已经有了可以执行的 I/O 回调函数,所以会进入 I/O callbacks 阶段,执行fs.readFile的回调函数。这个回调函数需要 200ms,也就是说,在它执行到一半的时候,100ms 的定时器就会到期。但是,必须等到这个回调函数执行完,才会离开这个阶段。</p><p>第三轮事件循环,已经有了到期的定时器,所以会在 timers 阶段执行定时器。最后输出结果大概是200多毫秒。</p><p>八、setTimeout 和 setImmediate</p><p>由于setTimeout在 timers 阶段执行,而setImmediate在 check 阶段执行。所以,setTimeout会早于setImmediate完成。</p><pre class="brush:php;toolbar:false">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执行。

相关推荐:

javascript定时器实现进度条功能

JavaScript基于定时器实现进度条的实例

nodejs中使用HTTP分块响应和定时器示例代码

以上がノードタイマーの詳細な分析の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

C/CからJavaScriptへ:すべてがどのように機能するかC/CからJavaScriptへ:すべてがどのように機能するかApr 14, 2025 am 12:05 AM

C/CからJavaScriptへのシフトには、動的なタイピング、ゴミ収集、非同期プログラミングへの適応が必要です。 1)C/Cは、手動メモリ管理を必要とする静的に型付けられた言語であり、JavaScriptは動的に型付けされ、ごみ収集が自動的に処理されます。 2)C/Cはマシンコードにコンパイルする必要がありますが、JavaScriptは解釈言語です。 3)JavaScriptは、閉鎖、プロトタイプチェーン、約束などの概念を導入します。これにより、柔軟性と非同期プログラミング機能が向上します。

JavaScriptエンジン:実装の比較JavaScriptエンジン:実装の比較Apr 13, 2025 am 12:05 AM

さまざまなJavaScriptエンジンは、各エンジンの実装原則と最適化戦略が異なるため、JavaScriptコードを解析および実行するときに異なる効果をもたらします。 1。語彙分析:ソースコードを語彙ユニットに変換します。 2。文法分析:抽象的な構文ツリーを生成します。 3。最適化とコンパイル:JITコンパイラを介してマシンコードを生成します。 4。実行:マシンコードを実行します。 V8エンジンはインスタントコンピレーションと非表示クラスを通じて最適化され、Spidermonkeyはタイプ推論システムを使用して、同じコードで異なるパフォーマンスパフォーマンスをもたらします。

ブラウザを超えて:現実世界のJavaScriptブラウザを超えて:現実世界のJavaScriptApr 12, 2025 am 12:06 AM

現実世界におけるJavaScriptのアプリケーションには、サーバー側のプログラミング、モバイルアプリケーション開発、モノのインターネット制御が含まれます。 2。モバイルアプリケーションの開発は、ReactNativeを通じて実行され、クロスプラットフォームの展開をサポートします。 3.ハードウェアの相互作用に適したJohnny-Fiveライブラリを介したIoTデバイス制御に使用されます。

next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する(バックエンド統合)Apr 11, 2025 am 08:23 AM

私はあなたの日常的な技術ツールを使用して機能的なマルチテナントSaaSアプリケーション(EDTECHアプリ)を作成しましたが、あなたは同じことをすることができます。 まず、マルチテナントSaaSアプリケーションとは何ですか? マルチテナントSaaSアプリケーションを使用すると、Singの複数の顧客にサービスを提供できます

next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)next.jsを使用してマルチテナントSaaSアプリケーションを構築する方法(フロントエンド統合)Apr 11, 2025 am 08:22 AM

この記事では、許可によって保護されたバックエンドとのフロントエンド統合を示し、next.jsを使用して機能的なedtech SaaSアプリケーションを構築します。 FrontEndはユーザーのアクセス許可を取得してUIの可視性を制御し、APIリクエストがロールベースに付着することを保証します

JavaScript:Web言語の汎用性の調査JavaScript:Web言語の汎用性の調査Apr 11, 2025 am 12:01 AM

JavaScriptは、現代のWeb開発のコア言語であり、その多様性と柔軟性に広く使用されています。 1)フロントエンド開発:DOM操作と最新のフレームワーク(React、Vue.JS、Angularなど)を通じて、動的なWebページとシングルページアプリケーションを構築します。 2)サーバー側の開発:node.jsは、非ブロッキングI/Oモデルを使用して、高い並行性とリアルタイムアプリケーションを処理します。 3)モバイルおよびデスクトップアプリケーション開発:クロスプラットフォーム開発は、反応および電子を通じて実現され、開発効率を向上させます。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

MantisBT

MantisBT

Mantis は、製品の欠陥追跡を支援するために設計された、導入が簡単な Web ベースの欠陥追跡ツールです。 PHP、MySQL、Web サーバーが必要です。デモおよびホスティング サービスをチェックしてください。

SAP NetWeaver Server Adapter for Eclipse

SAP NetWeaver Server Adapter for Eclipse

Eclipse を SAP NetWeaver アプリケーション サーバーと統合します。

VSCode Windows 64 ビットのダウンロード

VSCode Windows 64 ビットのダウンロード

Microsoft によって発売された無料で強力な IDE エディター

SublimeText3 英語版

SublimeText3 英語版

推奨: Win バージョン、コードプロンプトをサポート!

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境