javascript - 使用 promise 等待触发的事件

标签 javascript promise async-await

在下面的代码中,thing是一个我无法控制的外部对象;我无法更改 thing 的事件系统的工作方式。当 fn 被调用时,我们返回一个 promise ,其执行者监听一个事件,然后开始等待一系列最终导致该事件被触发的函数:

function fn() {

  return new Promise(async function(resolve, reject) {

      // This handler must be attached before `c` is called
      thing.once('myEvent', function(e) {
        resolve(e.data); // done
      });

      // The order of these functions calls is important,
      // and they may produce errors that need to be handled.
      await a();
      await b();
      await c(); // this causes myEvent

  });

}

这工作正常,但是 I've been told这是一个 promise 反模式,我应该让 fn 成为一个 async 函数。我该怎么做?如果我将 fn 设为 async 函数,那么我如何从事件处理程序中解析 e.data

编辑:

我接受了 Bergi 的回答,因为它有助于解释反模式以及它如何应用于这种情况。话虽如此,我认为上面的代码更具可读性并且明确显示了正在发生的事情,所以我将保持原样。这不是菜鸟谴责最佳实践,只是对于我的用例而言,遵守规则会使事情变得比他们需要的更复杂。当然,这让我对某些人持开放态度 problems ,但在找到更好的方法之前,我只能忍受这一点。

最佳答案

不要在 Promise 构造函数中执行任何 awaiting - 你只应该在那里执行异步回调的 promisification:

async function fn() {
  await a();
  await b();
  await c(); // this causes myEvent
  return new Promise(function(resolve, reject) {
    thing.once('myEvent', function(e) {
      resolve(e.data); // done
    });
  });
}

启动最终导致事件发出的过程的东西通常也在 Promise 执行器回调中调用(以捕获同步异常),但通常它不会返回 promise 就像您的 c 函数一样。

也许这更好地表达了意图:

async function fn() {
  await a();
  await b();
  const {data} = await new Promise(resolve => {
    thing.once('myEvent', resolve);
    thing.c(); // this causes myEvent
  });
  return data;
}

当然,这是假设您只需要在调用其他事件后才开始监听该事件。如果您希望事件在此之前触发,那么您实际上是在进行并行执行竞赛——我建议在这种情况下使用 Promise.all:

async function fn() {
  await a();
  await b();
  const [{data}, cResult] = await Promise.all([
    new Promise(resolve => thing.once('myEvent', resolve)),
    c()
  ]);
  return data;
}

如果您的节点 v11.13.0 或更高版本,您可以使用 events.once method这样您就不必自己构建 promise - 它也能正确处理错误事件:

import { once } from 'events';

async function fn () {
  await a()
  await b()
  await c()
  await once(thing, 'myEvent')
}

关于javascript - 使用 promise 等待触发的事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43084557/

相关文章:

javascript - 智能卡插入/移除未触发

javascript - 我必须在 Next.js 项目中使用 express 吗?

javascript - 如果请求已处理,则阻止执行下一个路由器

javascript - 当用户在弹出菜单外单击时,我应该隐藏弹出菜单吗

c# - 如何让AsyncLocal流向 sibling ?

javascript - 部署到 Heroku 时异步功能不起作用

javascript - 为什么这个 readline 异步迭代器不能正常工作?

javascript - Service Worker 中的同步或顺序获取

javascript - 了解使用 AngularJS promises,它们将如何帮助解决这个问题

javascript - ESNext : What's the purpose of the `async` keyword?