如何防止Node.js在等待回调时退出?

mik*_*ikl 83 node.js

我有这样的代码:

var client = new mysql.Client(options);
console.log('Icanhasclient');

client.connect(function (err) {
  console.log('jannn');
  active_db = client;
  console.log(err);
  console.log('hest');

  if (callback) {
    if (err) {
      callback(err, null);
    }

    callback(null, active_db);
  }
});
Run Code Online (Sandbox Code Playgroud)

我的问题是Node运行时会立即终止.它打印'Icanhasclient',但没有调用回调内的console.log.

(本例中的mysqlnode-mysql.

有没有什么可以让node.js在退出之前等待回调完成?

geo*_*ert 47

回调未排队

节点一直运行,直到所有事件队列都为空.当调用诸如的调用时,会将回调添加到事件队列

  emmiter1.on('this_event',callback).
Run Code Online (Sandbox Code Playgroud)

已执行.此调用是模块开发人员编写的代码的一部分.

如果模块是来自同步/阻塞版本的快速端口,则可能不会发生这种情况,直到操作的某些部分完成并且所有队列在此之前可能为空,从而允许节点以静默方式退出.

这是一个偷偷摸摸的bug,也就是模块开发人员在开发过程中可能不会遇到的错误,因为在繁忙的系统中,它会在很多队列中发生,因为在关键时刻它们都很少是空的.

用户可能的修复/错误检测器是在可疑函数调用之前插入特殊的计时器事件.

  • **警告**-尽管有很多反对意见,但我认为此答案中的信息不正确。调用EventEmitter.on()不会“不”添加任何内容到Node将等待的事件循环中(至少在当前版本的Node中)。似乎只有设置超时和从核心库进行异步调用之类的事情才能做到这一点。您可以通过编写一个单行程序轻松地测试此程序,该程序期望一个永远不会触发的事件。从这个答案中,您希望它永远不会终止,但是它确实会立即终止。[查看此答案](/sf/answers/3284162101/)了解更多信息。 (2认同)

小智 37

您可以使用setInterval发出setTimeout或重复超时.

如果要检查退出条件,还可以执行条件超时:

(function wait () {
   if (!SOME_EXIT_CONDITION) setTimeout(wait, 1000);
})();
Run Code Online (Sandbox Code Playgroud)

把它放在你的代码的末尾,控制台就会等待......等待...直到你想让它关闭.

  • 这是一个很好的解决方法,但不是一个漂亮的解决方案(什么不是你的错,而是节点). (4认同)

you*_*786 11

我的解决方案是实例化一个EventEmitter,并监听我的自定义事件.

var eventEmitter = new process.EventEmitter();
Run Code Online (Sandbox Code Playgroud)

然后我eventEmitter.emit从异步回调中调用:

client.connect(function (err) {
    eventEmitter.emit('myevent', {something: "Bla"})
});
Run Code Online (Sandbox Code Playgroud)

我脚本中的最后一件事是eventEmitter.on:

eventEmitter.on('myevent', function(myResult){
  // I needed the result to be written to stdout so that the calling process could get it
  process.stdout.write(JSON.stringify(myResult));
});
Run Code Online (Sandbox Code Playgroud)

然后节点将等待,直到事件处理程序完成运行.

  • EventEmitter类由events模块定义。因此,创建一个新的发射器:`const EventEmitter = require('events'); var eventEmitter = new EventEmitter()`。 (2认同)

Fra*_*cia 6

根据@Todd 的回答,我创建了一个单线。将其包含在脚本的开头,并done = true在完成后设置:

var done = (function wait () { if (!done) setTimeout(wait, 1000) })();
Run Code Online (Sandbox Code Playgroud)

例子:

var done = (function wait () { if (!done) setTimeout(wait, 1000) })();

someAsyncOperation().then(() => {
  console.log('Good to go!');
  done = true;
});
Run Code Online (Sandbox Code Playgroud)

它是如何工作的?如果我们稍微扩展一下:

// Initialize the variable `done` to `undefined`
// Create the function wait, which is available inside itself
// Note: `var` is hoisted but `let` is not so we need to use `var`
var done = (function wait () {

  // As long as it's nor marked as done, create a new event+queue
  if (!done) setTimeout(wait, 1000);

  // No return value; done will resolve to false (undefined)
})();
Run Code Online (Sandbox Code Playgroud)

  • 为什么你要对 IIFE 的输出设置 did,简单的 false 会更好。 (2认同)
  • @tiffon 可能只是为了让它成为一句俏话。 (2认同)