在事件发射器中使用异步

cyb*_*bat 1 asynchronous node.js eventemitter

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

这是来自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);
    }
});
Run Code Online (Sandbox Code Playgroud)

我发现了这篇文章建议进行一些有意义的切换,但是我无法正确地将其应用于此。

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

Nik*_*des 5

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

它是一个event处理程序回调,这一事实没有任何区别,因为最后它只是一个普通的Function

节点片段

'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')
Run Code Online (Sandbox Code Playgroud)

替代方案

如果您仍然无法使用它,可能是因为transporter.onEventEmitter.on-含义不同-这是由所提供的自定义函数transporter

在内部可以假定提供的回调函数不是Promise-记住将函数标记为会async强制该函数始终隐式返回a 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')
Run Code Online (Sandbox Code Playgroud)

  • 您确定不想将“myEmitter”重命名为“whoLetTheDogs”,并在“out”上设置侦听器吗? (2认同)