当前位置: 首页 > 面试题库 >

节点无错误退出并且不等待诺言(事件回调)

缑文栋
2023-03-14
问题内容

我遇到了一个非常奇怪的问题,即等待已将Promise传递resolve给事件-发射器回调的Promise会无错误地退出该过程。

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”。但是我得到的输出是:

条目
添加了侦听器

然后nodejs进程正常终止。

我认为这是什么做的垃圾收集器,但evtask显然还是在范围main。因此,我对如何完全退出该过程而没有错误感到无所适从。

很显然,我 最终发出的事件,但我已经简化我的代码上面的重现。我在node v8.7.0。我的代码有问题吗?或者这是节点错误?


问题答案:

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

基本上,节点保留已调度的异步请求(例如setTimeouts网络请求等)的参考计数。每调度一次,该计数就会增加,而每完成一次,该计数就会减少。如果到达事件循环周期的末尾,并且引用计数为零,则退出节点。

简单地创建一个Promise或事件发射器并 不会 增加引用计数-
创建这些对象实际上并不是异步操作。例如,此promise的状态将始终处于待处理状态,但过程将立即退出:

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

p.then(console.log)

同样,在创建发射器并注册侦听器之后,这也会退出:

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

如果您希望Node等待从未计划的事件,那么您可能会想到Node不知道将来是否可能发生事件,但是这样做是因为每次计划一个事件时都会计数。

因此,请考虑以下小改动:

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()。与前面的示例不同,这将立即退出:

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


 类似资料:
  • 问题内容: 我读到用关键字标记的异步函数隐式返回一个promise: 但这不连贯…假设返回一个诺言,而await关键字将从诺言中返回值,而不是诺言itsef,那么我的getVal函数 应该 返回该值,而不是隐式诺言。 那到底是什么情况?用async关键字标记的函数是隐式返回promise还是控制它们返回的内容? 也许,如果我们不明确地返回某些东西,那么他们会隐式地返回一个诺言…? 更清楚地说,上述

  • 我忙于处理一些以意想不到的方式(对我)响应的代码。它涉及处理Node.jspromise异常。 我修改了下面的函数,这样它所做的就是失败 当我试图调用它并处理这个错误时,问题就出现了。如果我做了下面的事情,它会像我期望的那样工作,函数会失败,并执行返回的捕获,停止最后一个控制台日志的执行 尽管如此,如果我按照如下方式编写函数,它似乎不会返回,它仍然会执行最后一个控制台日志,而不考虑等待时间 如果这

  • 问题内容: 因此,我遇到了多个未知长度的promise链的情况。我希望在处理所有链条后执行一些操作。那有可能吗?这是一个例子: 在此示例中,我设置了一个承诺1,,2和3,这些承诺会在某个随机时间得到解决。然后,我将诺言添加到第一和第三的结尾。我想在所有链条都解决后解决。这是运行此代码时的输出: 有没有办法等待连锁解决? 问题答案: 当所有链条都解决后,我希望所有人解决。 当然,然后将每个链的承诺传

  • 本文向大家介绍承诺回调和异步/等待,包括了承诺回调和异步/等待的使用技巧和注意事项,需要的朋友参考一下 首先,我们必须了解两个主要概念 同步编程 异步编程 同步编程 它等待每个语句完成执行,然后再转到下一条语句。 如果语句不相互依赖,但是由于它们在队列中,它们仍在等待执行,则此方法可能会减慢应用程序的速度。 异步编程 在移动到下一条语句之前,它不等待当前语句完成执行。例如,调用Web服务并使用Ja

  • 问题内容: 我有这样的代码: 我的问题是,节点在运行时立即终止。它显示“ Icanhasclient”,但没有调用回调内的console.log。 (本例中的mysql是node- mysql 。 有什么办法可以使node.js在退出之前等待回调完成? 问题答案: 回调未排队 节点运行直到所有事件 队列 都为空。诸如以下的调用时,回调将添加到事件 队列 中 已执行。该调用是模块开发人员编写的代码的

  • 问题内容: 我对节点还很陌生,我刚刚了解了javascript中提供的async和await函数。我正在尝试在下面随附的代码段中实现此方法。以我的理解,数据库响应应该首先打印到控制台,然后“完成”,但是我无法使其正常工作。任何帮助将不胜感激。 也请尝试说明您所做的修复操作,因为我想了解我做错了什么。 问题答案: 您的函数中没有语句。 通常,这将导致函数返回,但是由于您声明了它,因此它导致其返回 立