【问题标题】:How I can turn this function into an async await function?我怎样才能把这个函数变成一个异步等待函数?
【发布时间】:2021-01-10 17:27:05
【问题描述】:

使用:MongoDB、Express、Mongoose、NodeJs。

我目前有一个 seedDB 函数,它需要几个月的数组并为“月份”集合播种。看起来像这样:

const monthData = [{
        month: 'January',
        shifts: []
    },
    {
        month: 'February',
        shifts: []
    },
    {
        month: 'March',
        shifts: []
    },
    {
        month: 'April',
        shifts: []
    },
    {
        month: 'May',
        shifts: []
    },
    {
        month: 'June',
        shifts: []
    },
    {
        month: 'July',
        shifts: []
    },
    {
        month: 'August',
        shifts: []
    },
    {
        month: 'September',
        shifts: []
    },
    {
        month: 'October',
        shifts: []
    },
    {
        month: 'November',
        shifts: []
    },
    {
        month: 'December',
        shifts: []
    }
];

function seedDB() {
    for (entry of monthData) {
        Month.create(entry, (err, created) => {
            if (err) console.log(err);
            else console.log(created);
        })
    }
}

问题是我需要按顺序播种几个月(使用这种方法并不总是发生这种情况),所以我觉得异步函数可能在这里工作,这告诉它只能提前创建下个月上个月播种时。

我看过无数关于 Promise 和 async await 的教程,但我仍然不完全理解如何应用这些逻辑。如果有人可以展示和解释我当前代码的异步/承诺替代方案,我将不胜感激......

【问题讨论】:

    标签: javascript node.js mongodb mongoose async-await


    【解决方案1】:

    两个补充。 seedDB 函数前面有一个 async 关键字,每个 Promise 前面有一个 await 关键字:

    async function seedDB() {
        for (entry of monthData) {
            await Month.create(entry, (err, created) => {
                if (err) console.log(err);
                else console.log(created);
            })
        }
    }
    

    for 循环现在不会继续,直到每个单独的 Promise 解决。

    编辑:由于Month.create() 可能不返回 Promise(它看起来像传统的 err/value 回调,您可能需要像这样手动将其包装在 Promise 中:

    async function seedDB() {
        for (entry of monthData) {
            await new Promise((resolvePromise, rejectPromise) =>
                Month.create(entry, (err, created) => {
                    if (err) {
                        rejectPromise();
                        console.log(err);
                    } else {
                        resolvePromise();
                        console.log(created);
                    }
                })
            });
        }
    }
    

    或者,如果您使用的是 Node,则可以利用 util.promisify -- 它采用回调样式函数并返回一个提供常规承诺的函数。

    const util = require('util');
    const createMonthPromise = util.promisify(Month.create);
    
    async function seedDB() {
        for (entry of monthData) {
            const created = await createMonthPromise(entry);
            console.log('Created!', created);
        }
    }
    

    More info on MDN

    await 表达式会导致异步函数执行暂停,直到 Promise 被解决(即完成或拒绝),并在完成后恢复异步函数的执行。恢复时,await 表达式的值是已实现的 Promise 的值。

    【讨论】:

    • 谢谢,看起来正是我想要的,但似乎没有什么不同......?月份仍在以任意顺序输入
    • 效果很好,谢谢!只是看到那段代码就让它点击了!
    【解决方案2】:

    您可以使用“bluebird”库中的 Promise.mapSeries

    在这篇文章中你可以看到例子和解释 https://medium.com/@ekeyur/bluebirds-map-and-mapseries-explained-by-cooking-pasta-7dd03a19ea61

    const Promise = require('bluebird');
    
       function seedDB() {
            return Promise.mapSeries(monthData, (month) => {
                return Month.create(month)
            });
       }
    
       async function test() {
            const result = await seedDB();
       }
    

    但我不建议您将记录存储在具有顺序依赖性的数据库中。检查你的架构和用例,也许你可以避免它。

    【讨论】:

      【解决方案3】:

      也许您可以使用“创建”回调来确保以前的条目是通过这种方式创建的:

      let i=0;
      let callback = ()=> {if (i< monthData.length){ seedDB(i); console.log(i, "seeded"); i++;} }
      
      function seedDB(index){
          Month.create(monthData[index], callback)    
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-14
        • 2020-06-23
        • 2019-10-30
        • 1970-01-01
        • 1970-01-01
        • 2019-07-12
        相关资源
        最近更新 更多