2011-06-22 66 views
64

我有这样的代码:如何防止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); 
    } 
}); 

我的问题是,节点立即终止,当我运行它。它打印'Icanhasclient',但没有任何console.log内部的回调被调用。

(在这个例子是mysql node-mysql

有什么可以做,使node.js的等待回调完成之前退出?

+1

你是什么意思防止退出?在所有回调完成之前Nodejs不会退出。这是一个单线程的过程。 – neebz

+2

@nEEbz:如果是这样,为什么我的脚本不执行回调而退出? – mikl

+0

这是连接到数据库的问题;我不太确定为什么它不会触发回调。它会给出任何错误吗? – neebz

回答

39

回拨不排队

节点运行,直到所有事件队列是空的。回调被添加到事件队列当呼叫如

emmiter1.on('this_event',callback). 

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

如果一个模块是一个同步/阻塞版本快速端口,这可能不会发生直到操作的某些部分已经完成,并发生前所有队列会清空,允许节点默默退出。

这是一个鬼鬼祟祟的错误,这是模块开发人员在开发过程中可能没有遇到的错误,因为在拥有许多排队队列的繁忙系统中发生次数会少一些,因为它们都是空的在关键时刻。

用户A可能的修复/错误检测器是可疑函数调用之前插入一个特殊的定时器事件。

+0

“这可能不会发生,直到部分操作已完成” - 您能否澄清这一点?可能在一段代码仍然运行之前退出,然后才有机会向事件队列添加回调? –

+0

我想这意味着如果库已经将代码转换为一个与新的异步版本同步的代码,则可能库创建者忘记排队回调,事件队列在执行过程中被清空,因此完成了未调用的回调。 –

0

我没有看felixge/node-mysql库,并没有看到到API中的命令client.connect的参考。这是你试图做出的实际召唤吗?(不要试图在这里挑剔)?无论如何,恕我直言,你需要更多地考虑Javascript是如何设计的,因为它使用的编程范例与大多数其他流行语言不同。

第一个问题,我在你的代码中看到的是,你还没有定义的回调,所以它实际上并不存在。我会假设console.log(回调)是未定义的。从你的代码中,匿名函数是client.connect函数的'回调函数'。你必须在更高的范围内定义你所称的'回调'。例如,我将定义一个函数myCallback,使其存在于比client.connect的匿名函数更高的范围内。查找Javacscript variable scope可能会很有用。

var myCallback(err, response) { 
     if (err) { 
     console.log('err:%s',err); 
     } else { 
     console.log('response:%s',response); 
     } 
    } 

    client.connect(err, function(response) { 
     // this anonymous function is the callback to client.connect, the var 
     // 'callback' would be undefined. 
     if (err) { 
     myCallback(err); 
     return; // Explicit call to return, else the lines below would run. 
     } 
     myCallback(null, response); 
    }); 

其次,如果你没有明确地在Javascript中调用return,那么函数将继续处理。我被这个myself咬了。最后,Javascript运行一个event-driven循环,这意味着它永远不会等待函数返回一个值,这就是为什么我们将所有这些回调放在首位。您可以强制Javascript行为不同,例如通过使用while循环直到条件成立。有关操作事件循环的各种策略,请参阅caolan的“异步”库。过度使用这些方法的主要缺点是您实际上可能会浪费CPU周期/阻塞,因为您可能应该使用更多回调并重新考虑程序的工作方式。

30

你可以只发出的setTimeout或在使用setInterval重复超时。

如果你想检查退出条件,你也可以做一个有条件的超时:

(function wait() { 
    if (!SOME_EXIT_CONDITION) setTimeout(wait, 1000); 
})(); 

在你的代码的结尾将这个,控制台也将只是等待...等待...直到你想关闭它。

+3

这是一个很好的解决方法,但不是一个漂亮的解决方案(什么不是你的错,而是节点的)。 – peterh

3

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

var eventEmitter = new process.EventEmitter(); 

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

client.connect(function (err) { 
    eventEmitter.emit('myevent', {something: "Bla"}) 
}); 

在我的剧本的最后一件事是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)); 
}); 

节点会再等到事件处理程序运行完。

+0

我正在越来越'process.EventEmitter不是一个构造函数'错误。你会建议什么? –

+0

L了解如何创建EventEmitter。 https://coligo.io/nodejs-event-emitter/似乎是一个很好的资源。可能是不同版本的Node已经改变了如何创建一个。 – you786

+0

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