【问题标题】:Waiting for async function in for loop等待 for 循环中的异步函数
【发布时间】:2019-03-30 02:05:36
【问题描述】:

我需要等待数组中每个对象的异步方法(调用我的数据库)。现在我有一个 for 循环遍历数组,调用每个对象的异步方法。异步功能成功,但我需要等待每个异步调用完成才能继续。做了一些研究,我发现 Promises 与 await 或其他方法相结合可以解决我的问题,但我无法弄清楚。这是我现在拥有的代码。

这是我的带有异步功能的课程

Vacation : class Vacation {
    constructor(id, destination, description, attendee_creator_id) {
        this.id = id;
        this.destination = destination;
        this.description = description;
        this.attendee_creator_id = attendee_creator_id;
        this.creator = undefined;
        this.votes = undefined;
    }
    find_creator(pool){
        return new Promise(function (resolve, reject) {
            var self = this;
            var query = "SELECT * FROM vacation_attendee WHERE id = " + self.attendee_creator_id;
            pool.query(query, function(error, result) {
                if (error) {
                    console.log("Error in query for vacation creator " + error);
                    return reject(error);
                }
            var creator = new attendee.VacationAttendee(result.rows[0].full_name, result.rows[0].email, result.rows[0].password_hash);
            self.creator = creator;
            console.log("creator found ----> " + self.creator.full_name + "in " + self.destination);
            resolve(true);
        });
      })
    }

这是我调用异步函数的方式

function get_all_vacations(callback) {
        var sql_vacations_query = "SELECT * FROM vacation";    
        pool.query(sql_vacations_query, function(error, vacations_query_result) {        
            if (error) {
                console.log("error in vacations query " + error);
                callback(error);
            }
            var all_complete = loop_through_vacations(vacations_query_result.rows, pool);
            callback(null, all_complete);
            });
    }


async function loop_through_vacations(vacations_incomplete, pool) {
    var all_vacations = [];
    for (var vacation_data of vacations_incomplete) {
        var vacation_at_index = new vac.Vacation(vacation_data.id, vacation_data.destination, vacation_data.description, vacation_data.attendee_creator_id);            
        vacation_at_index.find_creator(pool)
            .then(()=> {
                all_vacations.push(vacation_at_index);
            })
            .catch(error=> {
                console.log(error);
            });
        console.log("passed vacation " + vacation_at_index.destination);
    }
    return await Promise.all(all_vacations);
}

【问题讨论】:

    标签: node.js async-await es6-promise


    【解决方案1】:

    你做错了,你没有在你身上等待任何东西for-loop

    return await Promise.all(all_vacations); 不起作用,因为all_vacations 不是 Promise 数组。

    在你的情况下,我们有很多方法可以做到这一点,我的方法只是一个例子:创建一个数组来存储在你的for-loop 中创建的所有承诺,然后等到Promise.all 完成所有承诺语法。

    async function loop_through_vacations(vacations_incomplete, pool) {
      var all_vacations = [];
      var promises = []; // store all promise
      for (var vacation_data of vacations_incomplete) {
        var vacation_at_index = new vac.Vacation(vacation_data.id, vacation_data.destination, vacation_data.description, vacation_data.attendee_creator_id);
        promises.push( // push your promise to a store - promises
          vacation_at_index.find_creator(pool)
            .then(() => {
              all_vacations.push(vacation_at_index)
            })
            .catch((err) => {
              console.log(err); // Skip error???
            })
        );
      }
      await Promise.all(promises); // wait until all promises finished
      return all_vacations;
    }
    

    我不知道你为什么将async/awaitcallback 混合使用,我推荐async/await 用于任何情况:

    混合风格:

    function get_all_vacations(callback) {
      var sql_vacations_query = "SELECT * FROM vacation";
      pool.query(sql_vacations_query, async function(error, vacations_query_result) { // async
        if (error) {
          console.log("error in vacations query " + error);
          return callback(error); // return to break process
        }
        var all_complete = await loop_through_vacations(vacations_query_result.rows, pool); // await
        callback(null, all_complete);
      });
    }
    

    async/await:

    async function get_all_vacations() {
      var sql_vacations_query = "SELECT * FROM vacation";
      var rows = await new Promise((resolve, reject) => {
        pool.query(sql_vacations_query, function(error, vacations_query_result) {
          if (error) {
            console.log("error in vacations query " + error);
            return reject(error);
          }
          resolve(vacations_query_result.rows);
        });
      })
      var all_complete = await loop_through_vacations(rows, pool); // await
      return all_complete;
    }
    

    【讨论】:

    • 感谢您的所有意见,我将花一些时间研究它。我实施了您的建议,但现在代码只是挂起,我尝试执行 var all_vacations = get_all_vacations(); console.log(all_vacations) // 但我在控制台中看不到任何内容。
    • 所以你的代码推送的是同一个假期对象,我修改了它现在可以工作了。但我就是不明白它为什么要这么做。这就是我改变的vacation_at_index.find_creator(pool) .then((vacation) => {//i modified the Promise.resolve in my Vacation Class all_vacations.push(vacation) }) .catch((err) => { console.log(err); // Skip error??? }) );
    • 另外,我对我的东西的格式感到非常抱歉,我对这个 lol 有点陌生。
    【解决方案2】:

    对我来说,你可以尝试重新格式化你的 SQL 查询,代码会更干净,并且一次大查询比多次查询花费的时间更少。

    如果我了解您的数据库中的联接:

    SELECT * 
    FROM vacation_attendee AS attendee 
    INNER JOIN vacation ON vacation.attendee_creator_id = attendee.id
    -- WHERECLAUSEYOUWANT
    

    然后:

    async function get_all_vacations(callback){
        const allComplete = await makeThatBigQuery(); // + treat data as you want
        callback(null, allComplete);
    }
    

    在 get_all_vacations 的定义中,您不会等待 all_complete,因此在 all_complete 准备好之前调用回调

    【讨论】:

    • FrV,感谢您的建议,但我需要帮助等待 for 循环中的所有异步调用完成。
    • 只是更新答案,如果真的想继续你采取的方式,你必须在 get_all_vacations -> var all_complete = await loop_through_vacations(vacations_query_result.rows, pool 中返回prosime.all而不等待);
    【解决方案3】:

    这就是代码的 await/promises 部分的样子:

    function get_all_vacations(callback) {
        var sql_vacations_query = "SELECT * FROM vacation";    
        pool.query(sql_vacations_query, async function(error, vacations_query_result) {        
            if (error) {
                console.log("error in vacations query " + error);
                callback(error);
            }
            var all_complete = await loop_through_vacations(vacations_query_result.rows, pool);
            callback(null, all_complete);
        });
    }
    
    
    async function loop_through_vacations(vacations_incomplete, pool) {
        const promises = [];
        for (var vacation_data of vacations_incomplete) {
            var vacation_at_index = new vac.Vacation(vacation_data.id, vacation_data.destination, vacation_data.description, vacation_data.attendee_creator_id);            
            promises.push(vacation_at_index.find_creator(pool));
        }
        return await Promise.all(promises);
    }
    

    理想情况下,您应该删除所有回调(不确定 pool.query 方法是否支持 async/await)并将整个代码更改为 async/await 样式。此外,您应该使用 resolve(creator) 解析来自 'find_creator' 的承诺,以便在解决承诺时获得该值。

    【讨论】:

      猜你喜欢
      • 2021-11-13
      • 1970-01-01
      • 1970-01-01
      • 2019-07-02
      • 2021-09-09
      • 1970-01-01
      • 2021-10-18
      • 2020-12-14
      • 2018-09-25
      相关资源
      最近更新 更多