如何在继续使用函数之前等待循环中的所有回调

时间:2019-08-13 12:22:02

标签: node.js promise callback async-await

我有一个具有接收用户数据的功能,在该数据中,我有一个电子邮件数组,可以使用节点邮件程序在给定的电子邮件数组上发送电子邮件

现在,我正在尝试使用foreach循环来遍历数组,并且在每次迭代时,我都在使用回调函数来检查给定的电子邮件是否存在

(使用服务whoisxmlapi.com),该电子邮件将返回是否有效的电子邮件 然后,如果电子邮件有效,则通过nodemailer发送邮件,否则不是

回调工作正常,但是运行此foreach循环的功能在回调返回之前走得更远(我想等到所有电子邮件都已验证并发送后)

/* tried[1]  async here */  function sendMails(fields) { 
var transporter = nodemailer.createTransport({
    host: 'smtp.gmail.com',
    port: 587,
    secure: false,
    requireTLS: true,
    auth: {
        user: email_from,
        pass: password
    }
});
var mailOptions = {
    from: email_from,
    to: _send_to_.toString(),
    subject: fields.email_subject,
    text: fields.msg_type == 'text' ? fields.message_text : '',
    html: fields.msg_type == 'html' ? fields.message_text : ''
};
let __vs_status__ = {
    email: email,
    email_v: false,
    email_s: false
};
_send_to_ = fields.emails
_send_to_.forEach( /* tried[2]  async here */ email => {
    var verifyEmail = /* tried[2] await here */  verifyEmailExist(email, (ev) => {
        console.log(ev.smtpCheck)
        if (ev.smtpCheck == 'true') {

            __vs_status__.email_v = true
            transporter.sendMail(mailOptions, function (error, info) { //want to wait for this too but couldn't test bcz valid email wait was not working properly
                if (error) {
                    console.log(error);
                    __vs_status__.email_s = false
                } else {
                    __vs_status__.email_s = true
                }
            });
        }
        // console.log('pushing')
        __email__info.push(__vs_status__)
        //    console.log(__email__info)
    })
});
console.log(/* tried[1]  await here */ __email__info) // this prints before loop and callbacks gets completed (don't want that)
}

// ----------------------------- EMAILS EXIST CHECK CALLBACK ---------------
function verifyEmailExist(email, callback) {
console.log('callback ' + email)
var email = email;
var api_key = apikey;
var api_url = 'https://emailverification.whoisxmlapi.com/api/v1?';
var url = api_url + 'apiKey=' + api_key + '&emailAddress=' + email;
https.get(url, function (response) {
    var str = '';
    response.on('data', function (chunk) {
        str += chunk;
    });
    response.on('end', function () {
        callback(JSON.parse(str));
    });
}).end();
}

我希望foreach循环在继续操作之前完成,并在for每个循环中验证电子邮件和发送状态

只是无法完成

我尝试了async / await,但是没有用(尝试过[reference] async / tryd [reference] await)

您只需安装所需的节点程序包,然后将一系列电子邮件传递给sendMails函数即可进行代码测试(并验证电子邮件,您需要使用api键)

2 个答案:

答案 0 :(得分:2)

async / await在这里并不重要,因为它实际上将包装/解开承诺(您不能使用的承诺)

我真的没有在这里看到问题。您的console.log(__email__info)和您的__email__info.push(__vs_status__)都必须位于transporter.sendMail的回调中

因此,以下内容:

_send_to_.forEach( /* tried[2]  async here */ email => {
  verifyEmailExist(email, (ev) => {
    console.log(ev.smtpCheck)
    if (ev.smtpCheck == 'true') {

        __vs_status__.email_v = true
        transporter.sendMail(mailOptions, function (error, info) { //want to wait for this too but couldn't test bcz valid email wait was not working properly
            if (error) {
                console.log(error);
                __vs_status__.email_s = false
            } else {
                __vs_status__.email_s = true
            }
            __email__info.push(__vs_status__)
            console.log(/* tried[1]  await here */ __email__info)
        });
    }
  })
});

答案 1 :(得分:0)

最好使用for循环,然后再使用每个循环,因为每个循环都包含回调。这里使用请求-承诺模块,因为它返回promise。 AND承诺util库的对象。这样可以将接受回调的方法转换为Promise。

const rp = require('request-promise'),
    {promisify} = require('util');

function sendMails(fields) {
    var transporter = nodemailer.createTransport({
        host: 'smtp.gmail.com',
        port: 587,
        secure: false,
        requireTLS: true,
        auth: {
            user: email_from,
            pass: password
        }
    });
    var mailOptions = {
        from: email_from,
        to: _send_to_.toString(),
        subject: fields.email_subject,
        text: fields.msg_type == 'text' ? fields.message_text : '',
        html: fields.msg_type == 'html' ? fields.message_text : ''
    };
    let __vs_status__ = {
        email: email,
        email_v: false,
        email_s: false
    };
    _send_to_ = fields.emails
    for (var email of _send_to_) {
        var ev = await verifyEmailExist(email)
            console.log(ev.smtpCheck)
            if (ev.smtpCheck == 'true') {

                __vs_status__.email_v = true
                const sendMail = promisify(transporter.sendMail).bind(transporter);
                const info = await sendMail(mailOptions);
                if (!info) {
                    console.log("error");
                    __vs_status__.email_s = false
                } else {
                    __vs_status__.email_s = true
                }
            }
            __email__info.push(__vs_status__)
    }
    console.log( /* tried[1]  await here */ __email__info) // this prints before loop and callbacks gets completed (don't want that)
}

// ----------------------------- EMAILS EXIST CHECK CALLBACK ---------------
async function verifyEmailExist(email, callback) {
    console.log('callback ' + email)
    var email = email;
    var api_key = apikey;
    var api_url = 'https://emailverification.whoisxmlapi.com/api/v1?';
    var url = api_url + 'apiKey=' + api_key + '&emailAddress=' + email;
    const str = await rp(url);
    return JSON.parse(str);
}