【问题标题】:Using async in event emitter在事件发射器中使用异步
【发布时间】:2017-11-23 05:59:43
【问题描述】:

我在尝试在事件中进行异步调用时遇到了挑战。

这是来自Nodemailer 的代码 - 我已经添加了需要进行异步调用的行:

let transporter = nodemailer.createTransport({
    SES: new aws.SES({
        apiVersion: '2010-12-01'
    }),
    sendingRate: 1 // max 1 messages/second
});

// Push next messages to Nodemailer
transporter.on('idle', () => {
    while (transporter.isIdle()) {

        // I need to make an async db call to get the next email in queue
        const mail = await getNextFromQueue()

        transporter.sendMail(mail);
    }
});

我发现了这个post,它建议交换一些东西,这是有道理的,但是我无法正确地应用它。

更新 - 答案是使用 Sinon 模拟 sendMail。

【问题讨论】:

  • 你不能把idle的回调标记为async,然后像往常一样在里面使用await吗?
  • 这似乎不起作用,因为这是我的第一次尝试。事件不会异步运行。如果你真的认为这应该有效,也许我犯了一个编码错误
  • 我已经添加了一个答案 - 但是 - 再想一想,如果你不能让它工作,那可能是因为 transporter.on 与 @ 不同987654328@。相反,它可以在内部假设提供的回调函数不是Promise,这或多或少是async 关键字的作用。我倾向于相信情况并非如此,但这是一种可能性。如果是这种情况,您可能希望将 async 包装在 IIFE 中

标签: node.js asynchronous eventemitter


【解决方案1】:

您可以将您的回调标记为async 并在其中使用await

事实上,它是一个 event 处理程序回调并没有什么区别,因为最后它只是一个普通的 Function

节点 sn-p

'use strict'

const EventEmitter = require('events')
const myEmitter = new EventEmitter()

const getDogs = () => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(['Woof', 'Woof', 'Woof'])
    }, 500)
  })
}

myEmitter.on('event', async () => {
  const dogs = await getDogs()
  console.log(dogs)
})

myEmitter.emit('event')

替代方案

如果您仍然无法使其工作,可能是因为 transporter.onEventEmitter.on 不同 - 这意味着它是 transporter 提供的自定义函数。

它可以在内部假设提供的回调函数不是 Promise - 请记住,将函数标记为 async 会强制函数始终隐式返回 Promise

如果是这种情况,您可能希望将 async 函数包装在 IIFE 中。

// ..rest of code from above

myEmitter.on('event', () => {
  // wrap into an IIFE to make sure that the callback 
  // itself is not transformed into a Promise
  (async function() {
    const dogs = await getDogs()
    console.log(dogs)
  })()
})

myEmitter.emit('event')

【讨论】:

  • 啊...我认为我的测试框架是问题所在。从 CLI 调用示例有效,但不适用于 Ava。我有我的外部函数 async 但由于没有任何返回承诺它只是结束。将不得不对此进行更多探索。
  • 不过值得一试。让我看看诗乃能不能帮忙。
  • 我得到了它的工作 - 谢谢你的建议。我最终模拟了sendMail,以检查它是否正在获取多封邮件和另一个测试,其中模拟了一些未显示的函数,该函数记录了邮件的结果并使用 nock 模拟了 SES 调用。
  • 您确定不想将myEmitter 重命名为whoLetTheDogs 并在out 上有一个监听器吗?
【解决方案2】:

我有类似的情况,如果我是你,我会做以下事情。

let transporter = nodemailer.createTransport({
SES: new aws.SES({
    apiVersion: '2010-12-01'
}),
sendingRate: 1 // max 1 messages/second
});

const sendMail = async () => {
    while (transporter.isIdle()) {
        // I need to make an async db call to get the next email in queue
        const mail = await getNextFromQueue()

        transporter.sendMail(mail);
    }
}

// Push next messages to Nodemailer
transporter.on('idle', sendMail);

【讨论】:

  • 根据 Nik 的回答,这与将 sendMail 函数内联为异步函数没有什么不同
猜你喜欢
  • 2018-12-05
  • 2013-09-21
  • 1970-01-01
  • 1970-01-01
  • 2016-02-10
  • 2015-07-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多