如何在for循环中等待异步函数执行完成?
解决异步调用等待所有完成的问题
我来帮你搞定这个等待所有异步数据库调用完成的问题~先梳理下你现有代码的核心问题,再一步步给出修复方案:
现有代码的核心问题
Promise.all使用错误:你传给Promise.all的是Vacation对象数组,但它需要接收Promise实例数组才能追踪并等待所有异步任务完成。- 异步任务未被追踪:循环里调用
find_creator后,只是通过.then悄悄push对象,没有把每个异步操作的Promise收集起来,导致无法判断所有任务是否完成。 this指向隐患:find_creator里的Promise回调用了普通函数,你用self = this虽然能绕开问题,但用箭头函数会更简洁安全。
修改后的完整代码
第一步:修复Vacation类的find_creator方法
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){ // 用箭头函数,this自动绑定当前Vacation实例,无需额外存self return new Promise((resolve, reject) => { var query = "SELECT * FROM vacation_attendee WHERE id = " + this.attendee_creator_id; pool.query(query, (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); this.creator = creator; console.log("creator found ----> " + this.creator.full_name + " in " + this.destination); resolve(this); // resolve时直接返回当前实例,方便后续收集 }); }) } }
第二步:修复loop_through_vacations函数
现在我们要主动收集每个异步任务的Promise,再用Promise.all等待全部完成:
async function loop_through_vacations(vacations_incomplete, pool) { // 用map遍历,把每个vacation数据转换成"加载完creator的Promise" const vacationPromises = vacations_incomplete.map(vacation_data => { const vacation = new vac.Vacation(vacation_data.id, vacation_data.destination, vacation_data.description, vacation_data.attendee_creator_id); // 返回find_creator的Promise,resolve后会得到填充好creator的实例 return vacation.find_creator(pool); }); // 等待所有异步任务完成,拿到最终的完整vacation数组 const all_vacations = await Promise.all(vacationPromises); console.log("所有vacation的创建者信息已加载完成"); return all_vacations; }
第三步:修复get_all_vacations函数
因为loop_through_vacations是async函数,会返回Promise,所以要正确处理它的结果:
function get_all_vacations(callback) { var sql_vacations_query = "SELECT * FROM vacation"; pool.query(sql_vacations_query, (error, vacations_query_result) => { if (error) { console.log("error in vacations query " + error); return callback(error); } // 调用async函数,用.then处理成功结果,.catch处理错误 loop_through_vacations(vacations_query_result.rows, pool) .then(all_complete => { callback(null, all_complete); }) .catch(err => { callback(err); }); }); }
关键逻辑说明
Promise.all的作用:它会等待传入的所有Promise都成功resolve后,返回一个包含所有resolve结果的数组;如果有任何一个Promise失败,会立即抛出对应的错误。- 用
map替代for循环:map可以更简洁地把原始数据转换成异步任务的Promise数组,避免手动维护数组的麻烦。 - resolve返回实例:在
find_creator里直接resolve当前Vacation实例,这样Promise.all完成后就能直接拿到所有已填充好数据的对象,无需额外处理。
这样修改后,就能确保所有异步数据库调用都完成后,才会执行后续的回调逻辑啦~
内容的提问来源于stack exchange,提问作者Gama
相关产品推荐
相关产品推荐

