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

我已经实现了一个callback的本地函数。 NodeJS知道这个接口,但是它并不知道它的实现。 这个本地函数接收到一个callback,并在结果准备就绪时调用它。 我不希望事件循环退出,而callback尚未被调用。

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

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

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

最好的方法是编写一个C ++插件,并使用libuv提供的一个 句柄 (当然,这是符合你的要求的 – 请参阅官方文档了解更多细节)。

如果你不想这样做,或者如果你不能这样做的话(如果我已经正确地理解了这个问题),其他答案中没有提到的可行的解决scheme是使用process.nextTick来调度函数,检查循环是否可以到期,
看到这里进一步的细节process.nextTick

作为一个最小的,工作的, 永无止境的例子:

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

这样,一旦执行完成,你的函数负责设置stop控制variables,循环将停止。

如果你有多个callback等待,只需使用一个计数器,并检查它寻找0。
如果您不希望在每次添加新函数时明确设置和更新计数器的值(容易出错),则可以轻松编写启动程序以启动增加计数器的函数,并安排下一步检查如果需要的话打勾
您也可以将callback作为额外的parameter passing给您的函数,以便在它们结束时进行通知,以便他们不必明确处理计数器本身。

使用下一个计时器的专用function的好处是,读者清楚你在做什么。
另一方面,虚假的服务器,未来计划的超时或I / Ostream的恢复和从未使用都是相当晦涩的,因为读者不知道你为什么这样做。

方法1:创build一个虚拟服务器(更新为多个callback):

 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:超时,callback结束进程

 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 

您也可以使用stdin Readablestream来保持退出循环。

 const callback = ffi.Callback('void', [], function() { // do your stuff here // switch stream out of flowing mode. process.stdin.pause(); }); // set stream into flowing mode ("old mode") process.stdin.resume(); lib.run_delayed(callback); 

参考 : https : //nodejs.org/api/process.html#process_process_stdin中的注释

在你的代码的某个地方启动repl,它会阻止你的应用程序退出。

 const repl = require('repl'); repl.start('> ') 

当你完成后打电话

 process.exit() 

https://nodejs.org/api/repl.html

造成很大的超时 – 它会阻止节点退出,同时也防止你无限期地等待(外部节点)结果:

 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