节点退出时没有错误,并且没有等待承诺(事件回调) [英] Node exits without error and doesn't await promise (Event callback)

查看:98
本文介绍了节点退出时没有错误,并且没有等待承诺(事件回调)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个非常奇怪的问题,等待一个已经通过其解决的Promise到事件 - 发射器回调只是退出进程而没有错误。

I've got a really weird issue whereby awaiting a Promise that has passed its resolve to an event-emitter callback just exits the process without error.

const {EventEmitter} = require('events');

async function main() {
  console.log("entry");

  let ev = new EventEmitter();

  let task =  new Promise(resolve=>{
    ev.once("next", function(){resolve()}); console.log("added listener");
  });

  await task;

  console.log("exit");
}

main()
.then(()=>console.log("exit"))
.catch(console.log);

process.on("uncaughtException", (e)=>console.log(e));

我期待这个过程在我运行时暂停,因为显然next当前从未发出。但我得到的输出是:

I'm expecting the process to halt when I run this because clearly "next" is currently never emitted. but the output I get is:


entry

添加了监听器

entry
added listener

然后nodejs进程正常终止。

and then the nodejs process terminates gracefully.

我认为这与垃圾收集器有关,但是 ev 任务显然仍在 main 的范围内。所以我真的不知道为什么这个过程完全没有错误地退出。

I thought it was something to do with the Garbage Collector, but ev and task are clearly still in scope on main. So I'm really at a loss as to why the process exits entirely without error.

显然我最终发出事件,但我已经将我的代码简化为上面的内容来重现。我在节点v8.7.0 。我的代码有问题还是这个节点错误?

Obviously I would eventually emit the event, but I've simplified my code to the above to reproduce. I'm on node v8.7.0. Is there something wrong with my code or is this a node bug?

推荐答案

这个问题基本上是:节点如何决定是否退出事件循环或再次转转?

This question is basically: how does node decide whether to exit the event loop or go around again?

基本上节点保持计划的异步请求的引用计数 - setTimeouts ,网络请求等。每次安排一次,该计数增加,每次完成一次,计数减少。如果你到达事件循环周期结束并且引用计数是零节点退出。

Basically node keeps a reference count of scheduled async requests — setTimeouts, network requests, etc.. Each time one is scheduled, that count increases, and each time one is finished, the count decreases. If you arrive at the end of an event loop cycle and that reference count is zero node exits.

只需创建一个承诺或事件发射器增加引用计数 - 创建这些对象实际上不是异步操作。例如,此承诺的状态将始终处于暂挂状态,但该过程会立即退出:

Simply creating a promise or event emitter does not increase the reference count — creating these objects isn't actually an async operation. For example, this promise's state will always be pending but the process exits right away:

const p = new Promise( resolve => {
    if(false) resolve()
})

p.then(console.log)

同样,在创建发射器并注册监听器后,它也会退出:

In the same vein this also exits after creating the emitter and registering a listener:

const ev = new EventEmitter()
ev.on("event", (e) => console.log("event:", e))

如果您希望Node等待从未调度过的事件,那么您可能会认为Node不知道是否存在是可能的未来事件,但确实如此,因为它会在每次安排时保持计数。

If you expect Node to wait on an event that is never scheduled, then you may be working under the idea that Node doesn't know whether there are future events possible, but it does because it keeps a count every time one is scheduled.

所以请考虑这个小改动:

So consider this small alteration:

const ev = new EventEmitter()
ev.on("event", (e) => console.log("event:", e))

const timer = setTimeout(() => ev.emit("event", "fired!"), 1000)
// ref count is not zero, event loop will go again. 
// after timer fires ref count goes back to zero and node exits

作为一方请注意,您可以使用以下命令删除对计时器的引用: timeout.unref()。与前一个示例不同,这将立即退出:

As a side note, you can remove the reference to the timer with: timeout.unref(). This, unlike the previous example, will exit immediately:

const ev = new EventEmitter()
ev.on("event", (e) => console.log("event:", e))

const timer = setTimeout(() => ev.emit("event", "fired!"), 1000)
timer.unref()

有一个很好的谈论Bert Belder的事件循环清除了很多误解: https://www.youtube.com / watch?v = PNa9OMajw9w

There's a good talk about the event loop by Bert Belder here that clears up a lot of misconceptions: https://www.youtube.com/watch?v=PNa9OMajw9w

这篇关于节点退出时没有错误,并且没有等待承诺(事件回调)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆