node.js 無限 NodeJS イベント ループが終了するのを防ぐには?




イベントループ スレッド (4)

私はコールバックを取るネイティブ関数を実装しました。 NodeJSはインターフェースを知っていますが、その実装については何も知りません。 このネイティブ関数はコールバックを受け取り、結果が準備できたときにそれを呼び出します。 コールバックが呼び出されていない間にイベントループを終了させたくありません。

これがそのような問題の例です

現在、NodeJSに自分の機能を待たせるために、(たとえそれがダムタイムアウトであっても)何らかの入出力を行う必要があります。

Boost.Asioでは、 workオブジェクトをインスタンス化し、コールバックが呼び出されたときにそれを破棄します 。 このオブジェクトが残っている間、Boost.Asioのイベントループは終了しませんでした。 NodeJSに同様のアプローチはありますか? 私はNodeJSで何を使用しますか(あなたの答えがタイマーについて言及していない場合のボーナス)?



方法1:ダミーサーバーを作成します(マルチコールバック用に更新)。

var counter = 0;

var server = require('net').createServer().listen(); // <-- Dummy server
console.log('Dummy server start.');

var ffi = require('ffi'),
    ref = require('ref')

var lib = ffi.Library('./libffi_async_demo', {
  'print_thread_id': [ 'void', [] ],
  'run_delayed': [ 'void', [ 'pointer' ] ],
});

var checkExit = function (){
  counter--;
  if (counter===0) {
    server.close(); // <-- exit Dummy Server
    console.log('Dummy server stop.');
  }
}

// Wrapper for lib.run_delay()
run_delay = function(cb) {
  counter++; // <-- increase counter
  lib.run_delayed(cb);
}

var callback1 = ffi.Callback('void', [], function() {
  console.log("js callback1 started");
  lib.print_thread_id();
  console.log("js callback1 finished");

  checkExit(); // <-- call at the end of each callback
})

var callback2 = ffi.Callback('void', [], function() {
  console.log("js callback2 started");
  lib.print_thread_id();
  console.log("js callback2 finished");

  checkExit(); // <-- call at the end of each callback
})

var callback3 = ffi.Callback('void', [], function() {
  console.log("js callback3 started");
  lib.print_thread_id();
  console.log("js callback3 finished");

  checkExit(); // <-- call at the end of each callback
})

run_delay(callback1); // use wrapper
run_delay(callback2); // use wrapper
run_delay(callback3); // use wrapper

方法2:タイムアウトが長い、コールバック終了プロセス

var timeout; // Hold timeout reference from setTimeout()

var ffi = require('ffi'),
    ref = require('ref')

var lib = ffi.Library('./libffi_async_demo', {
  'print_thread_id': [ 'void', [] ],
  'run_delayed': [ 'void', [ 'pointer' ] ],
});

var callback = ffi.Callback('void', [], function() {
  console.log("js callback started");
  lib.print_thread_id()
  console.log("js callback finished");

// Use one of the following 3:

//timeout.unref(); // <-- remove timer from Node event loop
//require('process').exit(); //<-- end process
  clearTimeout(timeout); // <-- cancel timer

})

lib.run_delayed(callback)

timeout = setTimeout(function() { }, 3600000); // <-- reasonably long timeout, eg. 1hr

そのための最善の方法は、 C ++アドオンを作成し、libuv handles提供するhandles one of使用することです(もちろん、あなたの要求に合ったもの - 詳細については公式documentationを参照してください)。

それをしたくない場合、またはできない場合(つまり、私がその質問を正しく理解している場合)、他の答えに記載されていない実行可能な解決策はprocess.nextTickを使用しprocess.nextTickスケジュールすることです。ループが期限切れになるかどうかをティックごとにチェックする関数。
process.nextTick詳細については、 hereを参照してください。

最小限の、実用的な、 終わりのない例として、

var process = require('process')
var stop = false;
var f = function() { if(!stop) process.nextTick(f) }
f()

このようにして、実行が終了するとstop制御変数を設定する機能が担当され、その後ループが停止します。

待つべきコールバックが複数ある場合は、単純にカウンターを使用して0を探してチェックしてください。
新しい関数を追加するたびにカウンタの値を明示的に設定および更新したくない(エラーが発生しやすい)場合は、カウンタを増分して次のチェックをスケジュールする関数を起動するためのランチャーを簡単に書くことができます。必要ならばチェックしてください。
また、コールバックを関数に追加の引数として渡して、関数が終了したことを通知することもできます。これにより、関数はカウンタ自体を明示的に処理する必要がなくなります。

次のティックで予定されている専用の機能を使うことのプラスはあなたがしていることが読者に明らかであるということです。
反対に、偽のサーバ、将来予定されているタイムアウト、または再開されて使用されていないI / Oストリームは、あいまいになります。読者には、なぜそれをしているのかすぐにはわからないからです。


大きなタイムアウトを作成します - ノードが終了するのを防ぎ、また(ノードの外部の)結果を無期限に待つのを防ぎます。

var ffi = require('ffi'),
    ref = require('ref')

var ffiTimeout;
var lib = ffi.Library('./libffi_async_demo', {
  'print_thread_id': [ 'void', [] ],
  'run_delayed': [ 'void', [ 'pointer' ] ],
});

var ffiDidTimedOut = false;
var cancelFfi = function(timeoutCb) {
  return function() {
    ffiDidTimedOut = true;
    timeoutCb();
  }
}

var callback = ffi.Callback('void', [], function() {
  if (ffiDidTimedOut) {
    return; // sorry, we waited too long and already started doing something else
  }
  // all good, async ffi finished within expected time and we are back in our js land
  clearTimeout(ffiTimeout);
  lib.print_thread_id()
})

lib.run_delayed(callback)

// continueIfCancelledCallback is your continuation "what to do id ffi actually takes more than 20 seconds to run"
ffiTimeout = setTimeout(cancelFfi(continueIfCancelledCallback), 20000); // 20 seconds




node.js