ホームページ  >  記事  >  ウェブフロントエンド  >  Node.js_node.js でタイマーを使用して関数を定期的に実行する方法の詳細な説明

Node.js_node.js でタイマーを使用して関数を定期的に実行する方法の詳細な説明

WBOY
WBOYオリジナル
2016-05-16 16:39:341348ブラウズ

クライアント側の JavaScript プログラミングに精通している場合は、関数の実行を一定期間遅延できる setTimeout 関数と setInterval 関数を使用したことがあるかもしれません。たとえば、次のコードは Web ページに読み込まれると、1 秒後にページのドキュメントに「Hello there」を追加します。

コードをコピー コードは次のとおりです:
var oneSecond = 1000 * 1; // 1 秒 = 1000 x 1 ミリ秒
setTimeout(function() {

document.write('

こんにちは。

');

}, oneSecond);


setInterval を使用すると、指定した間隔で関数を繰り返し実行できます。次のコードが Web ページに挿入されると、「Hello there」が毎秒ページ ドキュメントに追加されます:

コードをコピーします コードは次のとおりです:
var oneSecond = 1000 * 1 // 1 秒 = 1000 x 1 ms
setInterval(function() {

document.write('

こんにちは。

');

}, oneSecond);


Web は長い間、単純な静的ページではなく、アプリケーションを構築するためのプラットフォームになってきたため、この種の同様の需要がますます高まっています。これらのタスク スケジュール機能は、開発者が定期的なフォーム検証、遅延リモート データ同期、または遅延応答を必要とする UI インタラクションを実装するのに役立ちます。 Node はこれらのメソッドも完全に実装します。サーバー側では、これらを使用して、キャッシュの有効期限、接続プールのクリーンアップ、セッションの有効期限、ポーリングなどの多くのタスクを繰り返したり遅延したりできます。

setTimeout 遅延関数を使用して を実行します

setTimeout は、指定された関数を将来 1 回実行するための実行計画を作成できます。次に例を示します。

コードをコピーします コードは次のとおりです:
var timeout_ms = 2000
; var timeout = setTimeout(function() {

console.log("タイムアウト!");

}、timeout_ms);


クライアント側の JavaScript とまったく同じように、setTimeout は 2 つのパラメーターを受け取ります。最初のパラメーターは遅延する必要がある関数で、2 番目のパラメーターは遅延時間 (ミリ秒単位) です。

setTimeout は内部オブジェクトであるタイムアウト ハンドルを返します。これをパラメータとして使用して、タイマーをキャンセルすることができます。それ以外の場合、このハンドルは効果がありません。

clearTimeout を使用して実行計画をキャンセルします

タイムアウト ハンドルを取得したら、次のように、clearTimeout を使用して関数の実行計画をキャンセルできます。


コードをコピー コードは次のとおりです:
var timeoutTime = 1000
; var timeout = setTimeout(function() {

console.log("タイムアウト!");

}, timeoutTime);

clearTimeout(タイムアウト);


この例では、タイマーはトリガーされず、「タイムアウト!」という言葉も出力されません。次の例のように、将来いつでも実行計画をキャンセルすることもできます。

コードをコピーします コードは次のとおりです:

var timeout = setTimeout(function A() {

console.log("タイムアウト!");

}、2000);

setTimeout(function B() {

                                                                                                                                                                                                                                                          
}, 1000);

このコードでは、2 つの遅延実行関数 A と B を指定しています。関数 A は 2 秒後に実行されるようにスケジュールされ、関数 B は 1 秒後に実行されるようにスケジュールされています。これは、関数 B が最初に実行され、関数 A の実行計画がキャンセルされるためです。したがって、A は決して実行されません。

関数の繰り返し実行計画の作成とキャンセル

setInterval は setTimeout に似ていますが、指定された間隔で関数を繰り返し実行します。これを使用すると、プログラムを定期的にトリガーして、クリーニング、収集、ロギング、データ取得、ポーリングなど、繰り返し実行する必要があるタスクを完了できます。

次のコードは、コンソールに毎秒「ティック」を出力します。


コードをコピー コードは次のとおりです:
var period = 1000
setInterval(function() {

console.log("tick");

}、ピリオド);


永久に実行したくない場合は、clearInterval() を使用してタイマーをキャンセルできます。

setInterval は、実行計画ハンドルを返します。これは、実行計画をキャンセルするための clearInterval のパラメータとして使用できます。

コードをコピーします コードは次のとおりです:
var 間隔 = setInterval(function() {
console.log("tick");

}, 1000);

// …

clearInterval(間隔);


process.nextTick を使用して、イベント ループの次のラウンドまで関数の実行を遅らせます

クライアント側の JavaScript プログラマは、setTimeout(callback,0) を使用してタスクを短期間遅延させることがあります。2 番目のパラメータは 0 ミリ秒で、保留中のイベントがすべて処理された後すぐに待機するように JavaScript ランタイムに指示します。このコールバック関数を実行します。この手法は、すぐに実行する必要のない操作の実行を遅らせるために使用されることがあります。たとえば、ユーザー イベントの処理後に、アニメーションの再生を開始したり、その他の計算を実行したりする必要がある場合があります。

Node では、文字通りの意味の「イベント ループ」と同様に、イベント ループはイベント キューを処理するループ内で実行され、イベント ループの作業プロセスの各ラウンドはティックと呼ばれます。

イベント ループが次の実行ラウンド (次のティック) を開始するたびに、コールバック関数を 1 回呼び出すことができます。これはまさに process.nextTick の原理であり、setTimeout と setTimeout は JavaScript ランタイム内の実行キューを使用します。イベントループを使用しません。

setTimeout(callback, 0) の代わりに process.nextTick(callback) を使用すると、キュー内のイベントが処理された直後にコールバック関数が実行されます。これは、JavaScript のタイムアウト キューよりもはるかに高速です (測定する CPU 時間)。 )。

次のように、イベント ループの次のラウンドまで関数を遅らせることができます:

コードをコピー コードは次のとおりです:

process.nextTick(function() {

my_expensive_computation_function();

});

注: プロセス オブジェクトは、Node 内の数少ないグローバル オブジェクトの 1 つです。

イベントループのブロック

Node と JavaScript のランタイムはシングルスレッドのイベント ループを使用し、ループするたびに、関連するコールバック関数を呼び出してキュー内の次のイベントを処理します。イベントが実行されると、イベント ループは実行結果を取得して次のイベントを処理し、イベント キューが空になるまでこれが繰り返されます。いずれかのコールバック関数の実行に時間がかかる場合、その間、イベント ループは他の保留中のイベントを処理できなくなり、アプリケーションまたはサービスが非常に遅くなる可能性があります。

イベントを処理するときに、メモリに依存する関数やプロセッサに依存する関数が使用されると、イベント ループが遅くなり、大量のイベントが蓄積されて時間内に処理できなくなったり、キューがブロックされたりすることがあります。

イベント ループをブロックする次の例を見てください:

コードをコピー コードは次のとおりです:

process.nextTick(function nextTick1() {

var a = 0;

while(true) {

;

}

});

process.nextTick(function nextTick2() {

console.log("次のティック");

});

setTimeout(関数タイムアウト() {

console.log("タイムアウト");

}, 1000);


この例では、タイムアウト関数が後で実行されるようにスケジュールされている場合でも、イベント ループが nextTick 関数の無限ループによってブロックされているため、nextTick2 関数と timeout 関数はどれだけ待っても実行できません。 1秒間は実行されません。

setTimeout を使用すると、コールバック関数が実行計画キューに追加されますが、この例ではキューに追加されません。これは極端な例ですが、プロセッサを大量に使用するタスクを実行すると、イベント ループがブロックされたり、速度が低下したりする可能性があることがわかります。

イベントループを終了します

process.nextTick を使用すると、重要ではないタスクをイベント ループの次のラウンド (ティック) に延期できます。これにより、イベント ループが解放され、他の保留中のイベントの実行を継続できるようになります。

次の例を見てください。一時ファイルを削除する予定だが、データ イベントのコールバック関数がこの IO 操作を待機しないようにする場合は、次のように遅延できます。


コードをコピー コードは次のとおりです:
stream.on("データ", function(data) {
stream.end("私の応答");

process.nextTick(function() {

fs.unlink("/path/to/file");

});


関数実行の連続性を確保するには、setInterval の代わりに setTimeout を使用してください

特定の I/O 操作 (ログ ファイルの解析など) を実行できる my_async_function という関数を設計し、それを定期的に実行できるようにする予定だとします。次のように setInterval を使用して実装できます。

コードをコピー コードは次のとおりです:

var 間隔 = 1000;

setInterval(function() {

my_async_function(function() {

console.log('my_async_function が完了しました!');

},interval);//翻訳者注: 前の「,interval」は私が追加したもので、著者がタイプミスのために省略した可能性があります


これらの関数が同時に実行されないことを保証する必要がありますが、setinterval を使用する場合、my_async_function 関数の実行に interval 変数よりも 1 ミリ秒長くかかる場合、これらの関数は実行されます。順番ではなく同時に実行します。

訳者注: (以下の太字部分は訳者によって追加されたものであり、原書の内容ではありません)

コンテンツのこの部分の理解を容易にするために、作成者のコードを変更して実際に実行できるようにすることができます。

コードをコピーします コードは次のとおりです:
var 間隔 = 1000;
setInterval(function(){

(関数 my_async_function(){

setTimeout(function(){

console.log("1");

},5000);

},間隔);


このコードを実行して見てください。5 秒待つと、1 秒ごとに「hello」が出力されることがわかります。現在の my_async_function が実行された後 (5 秒かかります)、次の my_async_function を実行する前に 1 秒待機することが予想されます。各出力の間には 6 秒の間隔が必要です。この結果は、my_async_function がシリアルに実行されず、複数の関数が同時に実行されていることが原因で発生します。

したがって、ある my_async_function の実行終了と次の my_async_function の実行開始の間の間隔を、interval 変数で指定された時間と正確に強制する方法が必要です。これを行うことができます:


コードをコピー コードは次のとおりです:

var 間隔 = 1000 // 1 秒

(関数 subscription() { //3 行目

setTimeout(function do_it() {

my_async_function(function() { //5 行目

console.log('非同期が完了しました!');

スケジュール();

}、間隔);

}());


前のコードでは、schedule という関数が宣言され (3 行目)、宣言の直後に呼び出されます (10 行目)。このスケジュール関数は 1 秒後に do_it 関数を実行します (間隔で指定)。 1 秒後、5 行目の my_async_function 関数が呼び出され、実行が完了すると、独自の匿名コールバック関数 (6 行目) が呼び出され、この匿名コールバック関数によって do_it の実行計画が再度リセットされ、再度実行されます。 1 秒後、コードがループ内でシリアルかつ継続的に実行され始めます。

概要

setTimeout() 関数を使用して関数の実行計画を事前設定し、clearTimeout() 関数を使用してそれをキャンセルできます。 setInterval() を使用して関数を定期的に繰り返し実行することもできます。同様に、clearInterval() を使用してこの繰り返し実行計画をキャンセルすることもできます。

プロセッサ依存の操作を使用してイベント ループがブロックされると、当初実行されるようにスケジュールされていた関数が遅延されるか、まったく実行されないこともあります。したがって、イベント ループ内で CPU に依存する操作を使用しないでください。また、 process.nextTick() を使用して、イベント ループの次の反復まで関数の実行を遅らせることもできます。

I/O を setInterval() で使用する場合、どの時点でも保留中の呼び出しが 1 つだけであることを保証することはできません。ただし、再帰関数と setTimeout() 関数を使用すると、この厄介な問題を回避できます。

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