如何防止NodeJS事件循环退出?

vin*_*ker 11 node.js

我已经实现了一个需要回调的本机函数.NodeJS知道接口,但它对它的实现一无所知.此本机函数接收回调,并在结果准备好时调用它.我不希望在没有调用回调的情况下退出事件循环.

这是一个这样的问题的例子.

目前我需要做一些I/O(即使它是一个愚蠢的超时)来强制NodeJS等待我的功能.

Boost.Asio中,我只是实例化一个work对象并在调用回调时将其销毁.当这个对象被保留时,Boost.Asio的事件循环不会退出.NodeJS有类似的方法吗?我在NodeJS中使用什么(如果你的答案没有提及计时器,奖金)?

Joh*_*Siu 6

方法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
Run Code Online (Sandbox Code Playgroud)

方法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
Run Code Online (Sandbox Code Playgroud)


sky*_*ack 5

做到这一点的最好的办法是写一个C ++插件,并使用一个 把手由libuv提供的(当然,前提是符合您的要求之一-看到官方文档的其他细节)。

如果您不想这样做或不能这样做(就是这种情况,如果我正确理解了这个问题),则其他答案中未提及的可行解决方案是process.nextTick用来安排检查功能在每个滴答声中,循环是否可以终止。
请参阅此处以获取有关的更多详细信息process.nextTick

作为一个最小的,可行的,永无止境的示例:

var process = require('process')
var stop = false;
var f = function() { if(!stop) process.nextTick(f) }
f()
Run Code Online (Sandbox Code Playgroud)

这样,您的函数将在stop完成执行后负责设置控制变量,然后循环将停止。

如果要等待多个回调,只需使用一个计数器并检查它是否为0。
如果您不想每次添加新函数时都显式设置和更新计数器的值(容易出错),则可以可以轻松地编写启动程序来启动您的功能,以增加计数器并在需要时安排在下一个刻度上进行检查。
您还可以将回调作为额外的参数传递给函数,以在函数结束时进行通知,从而使它们不必显式处理计数器本身。

使用计划在下一个滴答滴答声中使用的专用功能的另一好处是,读者可以清楚地知道自己在做什么。
另一方面,伪造的服务器,将来计划的超时或恢复且从未使用过的I / O流非常模糊,因为读者无法立即知道为什么要这样做。