我已经实现了一个需要回调的本机函数.NodeJS知道接口,但它对它的实现一无所知.此本机函数接收回调,并在结果准备好时调用它.我不希望在没有调用回调的情况下退出事件循环.
这是一个这样的问题的例子.
目前我需要做一些I/O(即使它是一个愚蠢的超时)来强制NodeJS等待我的功能.
在Boost.Asio中,我只是实例化一个work对象并在调用回调时将其销毁.当这个对象被保留时,Boost.Asio的事件循环不会退出.NodeJS有类似的方法吗?我在NodeJS中使用什么(如果你的答案没有提及计时器,奖金)?
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)
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)
做到这一点的最好的办法是写一个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流非常模糊,因为读者无法立即知道为什么要这样做。