【问题标题】:How to wait for all callbacks in a loop before going further in function如何在进一步执行函数之前等待循环中的所有回调
【发布时间】:2019-12-20 00:07:33
【问题描述】:

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

现在我正在尝试使用 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 each 循环中验证电子邮件和发送状态

只是无法完成

我尝试过 async/await 但没有成功(尝试过[reference] async / 尝试过[reference] await)

您可以通过安装所需的节点包并将一组电子邮件传递给函数 sendMails 来测试代码(并且要验证电子邮件,您需要一个 api 密钥)

【问题讨论】:

    标签: node.js promise callback async-await


    【解决方案1】:

    async/await 在这里并不重要,因为它本质上会包装/解包 Promise(你没有使用)

    我真的没有看到这里有问题。您的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)
            });
        }
      })
    });
    

    【讨论】:

    • 我明白你的意思是将 email__info.push(__vs_status) 写入回调但我写了这个(console.log(__email__info)),因为针对一个函数调用(sendMails)我想执行其他操作在 foreach 结束后,例如针对一封电子邮件,我发送了 10 封邮件,所以无论电子邮件是否经过验证和发送,我都想一次性保存这 10 封邮件的数据(from_email),所以在保存所有数据之前,我需要所有回调要完成所以我一次保存数据而不是每次回调
    • 回调中的异步操作不会等待你的控制台日志......他们称之为“回调地狱”,因为最终你的代码看起来像楼梯。 Promise 将有助于代码的清洁,但仍然需要处理异步。所以,在伪:populateEmailInfo(/*add code here*/).then(emailInfo=>{/*do what you need*/})
    【解决方案2】:

    最好使用 for of 循环然后用于每个循环,因为每个循环都包含回调。这里使用 request-promise 模块,因为它返回 promise。以及 util 库的 promisify 对象。这样接受回调的方法就转化为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);
    }
    

    【讨论】:

    • @Divento 将其标记为答案,如果它解决了问题。
    猜你喜欢
    • 1970-01-01
    • 2019-06-17
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-15
    • 1970-01-01
    • 2022-12-10
    • 1970-01-01
    相关资源
    最近更新 更多