如何适时使用异步和同步编程

how to use asynchronous and synchronous programming in right time

我是 javascript 异步编程的新手。我有两个电子邮件提供商 sendgrid 和 mailgun。我想用其中一个发送电子邮件,然后如果发生任何错误,请重新发送另一个电子邮件。最后,如果电子邮件发送成功,则保存到数据库并使用 json 对象进行响应。 这是我的代码:

  if(req.query.provider== 'mailgun'){

      console.log('sending with mailgun ...');
      mailgun.messages().send(data, function (err, res) {
      if(err){
          fail = true;
          console.log(`error in sending email with mailgun. error :${err}`)
        } else {
          console.log('email sent with mailgun')
          fail = false;
        }
      });

    }else if(req.query.provider == 'sendgrid'){
      console.log('sending emial with sendgrid')
      sendgrid.sendMail(data, function(err, res) {
         if (err) {
               console.log(`error in sending with sendgrid. error: ${err} + response : ${res}`)
           fail = true
            }
             console.log(`email sent with sendgrid`)
           fail = false
         });
       }

       if(fail){
         if(req.query.provider == 'mailgun'){
           console.log('sending with sendgrid ...')
           sendgrid.sendMail(data, function(err, res){
             if(err){
               console.log(`error: ${err} + response : ${res}`)

             }else {
               console.log(`response: ${res}`)
               fail = false
             }
           })

         }else if(req.query.provider == 'sendgrid'){
            console.log('sendging with mailgun')
            mailgun.messages().send(data, function (err, res) {
              if(err){
              console.log(`error: ${err} + response : ${res}`)
            }else{
              console.log(`response: ${res}`)
              fail = false
            }
            })
         }
       }

  if(!fail){
      db.models.Email.create(req.query, (err, result)=>{
        if(err){
          handleErrors(res, err);
          console.log(`error in creating Email :${err}`)
        }else {
          console.log()
          res.json(result)
        }
      });
    } else {
          console.log('fail in sending error');
          res.json('sorry.');
        }
      });

这里的问题是,这段代码 运行 是异步的。例如,它使用 mailgun 发送,然后跳转到失败检查并使用 sendgrid 再次发送。不等待发送的响应。 我该如何解决和改进这个问题?我应该使用 async',await'?

您可以尝试 JavaScript 的延迟和承诺执行。请在没有延迟和承诺的情况下使用下面的第一个示例。在那之后,你会发现延迟和承诺执行是多么容易,

var firstData = null;
var secondData = null;

var responseCallback = function () {

    if (!firstData || !secondData)
        return;
    // do something
}

$.get("http://example.com/first", function (data) {
    firstData = data;
    responseCallback();
});

$.get("http://example.com/second", function (data) {
    secondData = data;
    responseCallback();
})

Then the same with deferred and promise,

var firstPromise = $.get("http://example.com/first");
var secondPromise = $.get("http://example.com/second");

$.when(firstPromise, secondPromise).done(function (firstData, secondData) {
    // do something
});

您可以在此处阅读更多内容 https://davidwalsh.name/write-javascript-promises

这里是一个使用 async/await 模式的例子

(可以改进以支持一般的多个邮件程序,您必须调整您 select alternativeMailerName 的部分).

  /**
   * Send an email using a given mailer
   *
   * return true if success, false otherwise
   */
  async sendMailUsingMessages(mailerName, data) {
    const {
      mailer,
      func,
    } = [
      {
        mailer: 'mailgun',
        func: async () => mailgun.messages().send(data);
      },
      {
        mailer: 'sendgrid',
        func: async () => sendgrid.sendMail(data);
      },
    ].find(x => x.mailer === mailerName);

    console.log(`sending with ${mailer} ...`);

    try {
      const res = await func();

      console.log(`email sent with ${mailer}`);

      return true;
    } catch (err) {
      console.log(`error in sending email with ${mailer}. error :${err}`)

      return false;
    }
  }

  /**
   * Send an email
   */
  async sendEmail(req, res, data) {
    if (!(await sendMailUsingMessages(req.query.provider, data))) {
      // One fail, so we try the other one
      const alternativeMailerName = req.query.provider === 'mailgun' ? 'sendgrid' : 'mailgun';

      if (!(await sendMailUsingMessages(alternativeMailerName, data))) {
        // Double fail
        console.log('fail in sending error');

        res.json('sorry.');

        return;
      }
    }

    // Success
    try {
      const result = await db.models.Email.create(req.query);

      res.json(result);
    } catch (err) {
      handleErrors(res, err);

      console.log(`error in creating Email :${err}`)
    }
  }