我有这样的代码:
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);
}
});
我的问题是Node运行时会立即终止。它打印'Icanhasclient',但回调中没有调用console.log。
(此示例中的mysql为node-mysql。
有没有什么可以让node.js在退出之前等待回调完成?
答案 0 :(得分:47)
回调未排队
节点一直运行,直到所有事件队列为空。当诸如
之类的调用时,会将回调添加到事件队列 emmiter1.on('this_event',callback).
已执行。此调用是模块开发人员编写的代码的一部分。
如果模块是同步/阻塞版本的快速端口,则可能不会发生这种情况,直到操作的某些部分完成并且所有队列在此之前可能为空,从而允许节点以静默方式退出。
这是一个偷偷摸摸的错误,也就是模块开发人员在开发过程中可能不会遇到的错误,因为在具有许多队列的繁忙系统中它会更少发生,因为它对于所有人来说都是罕见的他们在关键时刻是空的。
用户可能的修复/错误检测器是在可疑函数调用之前插入特殊的计时器事件。
答案 1 :(得分:37)
您可以使用setInterval发出setTimeout或重复超时。
如果要检查退出条件,还可以执行条件超时:
(function wait () {
if (!SOME_EXIT_CONDITION) setTimeout(wait, 1000);
})();
将此代码放在代码的末尾,控制台将等待...等待......直到您希望它关闭。
答案 2 :(得分:8)
我的解决方案是实例化一个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));
});
Node将等到事件处理程序完成运行。
答案 3 :(得分:2)
基于@Todd的回答,我创建了一个单行。将其包含在脚本的开头,并在完成后设置done = true
:
var done = (function wait () { if (!done) setTimeout(wait, 1000) })();
示例:
var done = (function wait () { if (!done) setTimeout(wait, 1000) })();
someAsyncOperation().then(() => {
console.log('Good to go!');
done = true;
});
它是如何工作的?如果我们稍微扩展一下:
// 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)
})();
答案 4 :(得分:0)
这是我的两分钱
async function main()
{
await new Promise(function () {});
console.log('This text will never be printed');
}
function panic(error)
{
console.error(error);
process.exit(1);
}
// https://stackoverflow.com/a/46916601/1478566
main().catch(panic).finally(clearInterval.bind(null, setInterval(a=>a, 1E9)));
答案 5 :(得分:0)
这就是我的方法。我让主入口点返回一个诺言,然后使用这个小包装程序确保只要未兑现诺言,节点就不会退出:
function wrapPromiseMain(entryPoint) {
const pollTime = 1000000;
let interval = setInterval(() => {}, pollTime);
return entryPoint().finally(() => {clearInterval(interval)});
}
要使用它,只需承诺您的主入口点并将其作为参数传递给包装器即可:
function main() {
// ... main stuff ...
return doSomethingAsync();
}
wrapPromiseMain(main);
我发现它比基本的轮询循环更整洁,因为它会在承诺履行时自动取消计时器,因此不会增加任何额外的延迟。因此,如果您愿意,轮询时间基本上可以是永久的。
答案 6 :(得分:-1)
我确实查看了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的'async'库。过度使用这些方法的主要缺点是,当您可能应该使用更多回调并且只是重新思考程序的工作方式时,实际上会浪费CPU周期/阻塞。
答案 7 :(得分:-1)
请尝试这个。检查是否有帮助。
var client = new mysql.Client(options);
console.log('Icanhasclient');
var verbose;
if (!verbose) {
return new Promise(function (resolve, reject) {
client.connect(function (err) {
if (err) {
console.log(Error in connecting
SQL ${err}
)
;
return reject(err);
}
verbose = client;
return resolve(verbose);
})
})
} else {
return new Promise(function (resolve) {
resolve(verbose);
})
}