首页 > 解决方案 > NODE JS:如何使以下调用等待被调用函数完成后再继续

问题描述

我仍然无法将注意力集中在 async/await 功能上,并且针对以下情况尝试了几种解决方案,但均未成功:

我有这个功能:

function addDataToDb(articleData) {

    initMongoDb();

    kanpionDb.on('error', console.error.bind(console, 'connection error:'));
    kanpionDb.once('open', function () {
        SiteUrlModel.init().then(() => {
            articleData.forEach(articleItem => {
                var article = new SiteUrlModel(articleItem).save(function (error) {
                    if (error) {
                        console.log("Failed: " + articleItem.siteName);
                    } else {
                        console.log("Success " + articleItem.siteName);
                    }
                });
            });
        });
    });
}

从另一个文件中调用它:

c.on('drain', async function () {
    Database.addDataToDb(ArticleList);
    console.log("All done");
});

问题:如何在执行完成console.log("All done")后只显示消息Database.addDataToDb(ArticleList)

标签: node.jsasync-await

解决方案


这个解决方案有点混乱,因为你在同一个函数中混合了大量的异步技术:事件、承诺和回调,然后最重要的是,有一个循环。这确实是一团糟,通常是您想要避免的。

这种复杂程度的最佳整体解决方案是备份几个步骤,并承诺所有基本异步操作比这高几个步骤。对于您的数据库,您应该去查找并使用数据库的 promise 接口。对于您的事件,由于这些都是一次性事件,您可以在对象上构建一个 Promise 包装器,以获取有关打开和错误事件的通知。

但是,由于我不知道您正在使用的所有组件,因此我无法真正为您完成这部分工作。因此,我们将看看我们可以做些什么来将适当的 Promise 级别的支持修补到这种混合技术中。

const {promisify} = require('util');

function addDataToDb(articleData) {
    return new Promise((resolve, reject) => {
        initMongoDb();

        kanpionDb.on('error', err => {
            console.error('connection error:', error);
            reject(error);
        });
        kanpionDb.once('open', function () {
            SiteUrlModel.init().then(() => {
                return Promise.all(articleData.map(articleItem => {
                    let model = new SiteUrlModel(articleItem);
                    model.savePromise = promisify(model.save);
                    return model.savePromise().then(() => {
                        console.log("Success " + articleItem.siteName);
                    }).catch(err => {
                        console.log("Failed: " + articleItem.siteName);
                        throw err;
                    });
                }));
            }).then(resolve, reject);
        });
    });
}

// usage:
addDataToDb(articleData).then(() => {
    console.log("All Done");
}).catch(err => {
    console.log(err);
});

技术总结:

  1. 由于这些事件,我们将不得不包装一个手动创建的 Promise,我们在完成时解决或拒绝该 Promise。
  2. .forEach()循环被替换为whichPromise.all(articleData.map(...))将给我们一个承诺,告诉我们何时完成所有保存。
  3. .save(callback)必须替换为.save(). 理想情况下,您只需在此处使用数据库接口的承诺版本,但我已经展示了如何在.save()必要时手动承诺该功能。
  4. 连接拒绝error事件。
  5. 连接决心并拒绝SiteUrlModel.init()承诺。
  6. Promise.all()承诺与SiteUrlModel.init()承诺联系起来。

推荐阅读