即使发生异常后如何继续异步外观?

时间:2020-04-24 09:59:31

标签: javascript asynchronous

在我的Node.js应用程序中,我有一个名为employees的数组,用于存储电子邮件列表。我解析了该列表,并尝试通过nodemailer软件包分别为每个人发送电子邮件。我也使用for-async包。

循环的一个迭代中可能发生错误。即使发生错误,我也想继续循环。看来我无法使用continue语句,您推荐什么解决方案?

const forAsync = require('for-async');

forAsync(employees, (employee) => {
    return new Promise(resolve => {
        // Set options.
        const options = {
            from: process.env.EMAIL,
            to: employee,
            subject: "System notification",
            html: html
        };

        // Send mail with defined transport object.
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                transporter.sendMail(options, (error) => {
                    if(error) {
                        console.log(error);
                        reject(error);
                    } else {
                        resolve();
                    }
                });
            }, 1000);
        }).then(() => {
            resolve();
        }).catch(error => {
            console.log(error);
        );
    });
});

编辑:

router.post('/notifications', function(request, response) {
    // Make sql requests to the database.

    Promise.all([firstQuery, secondQuery, thirdQuery]).then(responses => {
        // Some logic

        await Promise.all(employees.map(async (employee) => { // <- PROBLEM
            try {
                await sendEmail(transporter, options);
            } catch (error) {
                // Error sending this specific email, just report it and ignore
                console.log(error);
            }
        }));
    });
});

1 个答案:

答案 0 :(得分:2)

由于您使用的是Node.js的较新版本,因此我将使用async函数和一个for循环。

首先,由于transporter.sendEmail是旧的回调样式函数,因此我将在一些实用程序模块中为其创建包装器:

function sendEmail(transporter, options) {
    return new Promise((resolve, reject) => {
        transporter.sendMail(options, (error) => {
            if (error) {
                reject(error);
            } else {
                resolve();
            }
        });
    });
}

然后,循环(在async函数中)将是:

for (const employee of employees) {
    try {
        await sendEmail(transporter, {
            from: process.env.EMAIL,
            to: employee,
            subject: "System notification",
            html: html
        });
    } catch (error) {
        // Error sending this specific email, just report it and ignore
        console.log(error);
    }
}

try / catch防止任何错误或承诺拒绝传播到循环之外,因此循环继续进行。请注意,电子邮件将以系列发送,而不是以 parallel 发送。

假设您确实不需要一秒钟的延迟,那么我已经将其删除了,但是如果需要,可以在您的实用程序中添加一个delay函数:

function delay(ms, value) {
    return new Promise(resolve => setTimeout(resolve, ms, value));
}

然后将其插入for循环中:

await delay(1000);

如果您希望并行而不是串行执行此操作,则需要Promise.all和单个诺言的拒绝处理程序:

await Promise.all(employees.map(async (employee) => {
    try {
        await sendEmail(transporter, {
            from: process.env.EMAIL,
            to: employee,
            subject: "System notification",
            html: html
        });
    } catch (error) {
        // Error sending this specific email, just report it and ignore
        console.log(error);
    }
}));

await Promise.all(employees.map(employee => sendEmail(transporter, {
        from: process.env.EMAIL,
        to: employee,
        subject: "System notification",
        html: html
    }).catch(error) {
        // Error sending this specific email, just report it and ignore
        console.log(error);
    })
);
相关问题