【问题标题】:converting callback to async throws error将回调转换为异步会引发错误
【发布时间】:2018-07-18 01:24:12
【问题描述】:

以下代码有效:

  var smtpConfig = {
    host: 'localhost',
    port: 465,
    secure: true, // use SSL
    selfSigned: true
  };

  // create reusable transporter object using the default SMTP transport
  var transporter = nodemailer.createTransport(smtpConfig);

  // setup e-mail data with unicode symbols
  var mailOptions = {
    from: '"Some One" <someone@example.com>', // sender address
    to: 'validuser@company.com', // list of receivers
    subject: 'Hello', // Subject line
    text: 'Hello world ?', // plaintext body
    html: '<b>Hello world ?</b>' // html body
  };

  transporter.sendMail(mailOptions, (error, info) => {
      if (error) {
          console.log(error);
      } else {
          console.log(info);
      }
  });

但是,如果我从节点使用util.promisify

  var sendMail = promisify(transporter.sendMail);
  var info = await sendMail(mailOptions);

我遇到了异常

TypeError: Cannot read property 'getSocket' of undefined
  at sendMail (c:\Users\user\Source\project\node_modules\nodemailer\lib\mailer\index.js:143:25)
  at sendMail (internal/util.js:230:26)

问题在 sendMail 内部,因为 'this' 未定义:

/**
 * Sends an email using the preselected transport object
 *
 * @param {Object} data E-data description
 * @param {Function?} callback Callback to run once the sending succeeded or failed
 */
sendMail(data, callback) {
    let promise;

    if (!callback && typeof Promise === 'function') {
        promise = new Promise((resolve, reject) => {
            callback = shared.callbackPromise(resolve, reject);
        });
    }

    if (typeof this.getSocket === 'function') { <-- this is undefined
        this.transporter.getSocket = this.getSocket;
        this.getSocket = false;
    }

在普通函数上使用 util.promisify 是可行的。我想这是因为我在类方法上使用了util.promisify

有没有办法实现这一点,或者我是否需要使用 async function sendMail 重载扩展 exting 类

【问题讨论】:

  • util.promisify 不可能知道 sendMail 之前附加到的对象。
  • 您在滥用promisify。如果您想以您尝试的方式使用它,您将需要绑定上下文。 promisify 非常适合不需要状态的函数式函数。

标签: node.js typescript async-await es6-promise nodemailer


【解决方案1】:

要解决这种特殊情况,您可以使用

await sendMail.call(transporter, mailOptions) // provide a context

当然,查看transporter.sendMail()的源代码,它已经支持以thenable 的形式调用,无需包装util.promisify(),因此您可以直接await

await transporter.sendMail(mailOptions) // omit callback to kick in promise-style async

【讨论】:

  • 为什么投反对票?重复的目标需要util.promisfy(),而在这种情况下,知道这不是必需的会很有帮助。
  • 没有投反对票,但我很确定在这种情况下您仍然需要 bindtransporter 对吗?
  • @zero298 sendMail,来自promisify()的返回值是未绑定的。 .call()transporter 一起调用它会以它作为上下文来调用它。
  • 好吧,我不知道为什么投反对票,但两种解决方案都是正确的。谢谢并竖起大拇指。需要等待 5 分钟才能接受。
  • 你说得对,我仍然坚持使用 promisify。我实际上并没有注意到您使用的是call
猜你喜欢
  • 2014-07-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-11-24
  • 2012-03-15
  • 2015-10-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多