在 for 循环中等待异步函数
Waiting for async function in for loop
我需要等待数组中每个对象的异步方法(对我的数据库的调用)。现在我有一个 for 循环遍历数组,在每个对象上调用异步方法。异步函数成功,但我需要等待每个异步调用完成才能继续。通过一些研究,我发现 Promises 与 await 或其他方法相结合可以解决我的问题,但我一直无法弄清楚。这是我现在的代码。
这是我的 class 和异步函数
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);
}
对我来说,你可以尝试重新格式化你的 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 就绪之前调用回调
你做的方法不对,你什么都不等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/await
混合 callback
风格,我推荐 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;
}
代码的 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 方法是否支持 asyn/await)并将整个代码更改为 async/await 样式。此外,您应该使用 resolve(creator)
解析来自 'find_creator' 的承诺,以便在解决承诺时获得该值。
我需要等待数组中每个对象的异步方法(对我的数据库的调用)。现在我有一个 for 循环遍历数组,在每个对象上调用异步方法。异步函数成功,但我需要等待每个异步调用完成才能继续。通过一些研究,我发现 Promises 与 await 或其他方法相结合可以解决我的问题,但我一直无法弄清楚。这是我现在的代码。
这是我的 class 和异步函数
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);
}
对我来说,你可以尝试重新格式化你的 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 就绪之前调用回调
你做的方法不对,你什么都不等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/await
混合 callback
风格,我推荐 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;
}
代码的 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 方法是否支持 asyn/await)并将整个代码更改为 async/await 样式。此外,您应该使用 resolve(creator)
解析来自 'find_creator' 的承诺,以便在解决承诺时获得该值。