NodeJS异步循环中SQL查询结果无法正确存入数组问题排查
Node.js异步SQL查询循环中await不生效的问题解决
问题描述
本人习惯使用Java,近期启动了一个NodeJS项目,遇到异步逻辑相关问题。需要编写一个函数,循环执行SQL查询(每次迭代修改参数)并将结果存入数组。定义了数组变量let FINAL = [],尝试在每次查询返回数据时将结果push进去,但发现最后一行console.log("RESULT : " + FINAL)比循环内的console.log先执行,即使添加了await也无法解决问题。
代码如下:
const fluxAccesParPeriode = async (req, res) => { try { const db = res.locals.db; const {date_debut, date_fin} = req.body; if (!date_debut || !date_fin) { res.status(400).json({error: 'One or more informations are missing.'}); return; } // SQL const queryText = "SELECT COUNT(id_pointage) AS nbreAcces FROM pointage_adherents PA, adherents A WHERE PA.id_adherent=A.id_adherent AND date BETWEEN ? AND ? AND heure_entree BETWEEN ? AND ?"; let FINAL = []; for (let i = 0; i < 24; i += 3) { let heure_debut = i + ":00:00"; let heure_fin = (i + 3) + ":00:00"; await db.execute(queryText, [date_debut, date_fin, heure_debut, heure_fin], (err, results) => { if (err) { console.error('Error executing SQL query:', err); res.status(500).json({error: 'Internal Server Error'}); return; } console.log(heure_debut + " / " + heure_fin + " / " + results[0]["nbreAcces"]); FINAL.push({heure_debut: heure_debut, heure_fin: heure_fin, result: results[0]["nbreAcces"]}); }); } console.log("RESULT : " + FINAL); if (FINAL.length > 0) { res.status(200).json(FINAL); } else { res.status(400).json({error: 'Error while executing your query: fluxAccesParPeriode'}); } } catch (error) { console.error(error.stack); res.status(500).json({message: 'Erreur lors de l\'exécution de la requête'}); } }
问题原因
核心问题是**await只对返回Promise的函数生效**。你当前使用的db.execute是回调风格的API——它不会返回Promise,而是通过第三个参数的回调函数处理异步结果。所以你加的await根本没有等待查询完成,循环会直接走完,此时回调函数还没执行,FINAL数组自然是空的,最后一行的console.log也就先输出了。
解决方案
把回调风格的db.execute转换成Promise风格,这样await才能正确等待异步操作完成。可以用Node.js内置的util.promisify工具,或者直接使用数据库库提供的Promise版本方法。
修改后的代码示例
const util = require('util'); // 引入util模块 const fluxAccesParPeriode = async (req, res) => { try { const db = res.locals.db; // 将回调风格的execute转为Promise风格,bind绑定db上下文 const executeQuery = util.promisify(db.execute).bind(db); const {date_debut, date_fin} = req.body; if (!date_debut || !date_fin) { res.status(400).json({error: 'One or more informations are missing.'}); return; } const queryText = "SELECT COUNT(id_pointage) AS nbreAcces FROM pointage_adherents PA, adherents A WHERE PA.id_adherent=A.id_adherent AND date BETWEEN ? AND ? AND heure_entree BETWEEN ? AND ?"; let FINAL = []; for (let i = 0; i < 24; i += 3) { let heure_debut = i + ":00:00"; let heure_fin = (i + 3) + ":00:00"; // 用await等待Promise完成,直接获取结果 const results = await executeQuery(queryText, [date_debut, date_fin, heure_debut, heure_fin]); console.log(heure_debut + " / " + heure_fin + " / " + results[0]["nbreAcces"]); FINAL.push({heure_debut: heure_debut, heure_fin: heure_fin, result: results[0]["nbreAcces"]}); } console.log("RESULT : ", FINAL); // 改用逗号输出,避免数组转字符串显示异常 if (FINAL.length > 0) { res.status(200).json(FINAL); } else { res.status(400).json({error: 'Error while executing your query: fluxAccesParPeriode'}); } } catch (error) { console.error(error.stack); res.status(500).json({message: 'Erreur lors de l\'exécution de la requête'}); } }
额外说明
- 如果你的数据库库本身支持Promise(比如mysql2/promise),可以直接使用Promise版本的连接,这样就不需要
util.promisify,直接调用db.execute就能返回Promise。 - 原代码中在回调里调用
res.status(500)可能会出现重复响应的问题,改成Promise+await后,错误会被外层的try/catch统一捕获,处理响应更安全。
内容的提问来源于stack exchange,提问作者Abderaouf Boucenna
相关产品推荐
相关产品推荐

