如何使用Node.js与MySQL将数据存入数组?异步查询返回空数组问题排查
根本原因
- 该问题是典型的Node.js 异步 IO 执行顺序问题,MySQL 的
connection.query为异步非阻塞方法,回调函数仅会在 SQL 查询完成后才会执行,不会阻塞主线程代码运行 - 原代码在循环触发所有子查询请求后立刻执行了
res.send返回响应,此时所有子查询的回调都还未触发,arrStoreChildData未被推入任何数据,因此返回空数组
修复方案
方案一:async/await 写法(推荐)
先将 query 方法 promisify 化,用 async/await 控制执行顺序,代码可读性更高:
// 引入util模块的promisify方法将callback形式的query转为返回promise的方法 const util = require('util'); const query = util.promisify(connection.query).bind(connection); let categoryget = async (req, res) => { try { let arrStoreParentData = []; let arrStoreChildData = []; // 等待第一个父查询执行完成 const rst_parent = await query(` SOME SQL QUERY { FIRST QUERY } ='none'`); // 生成所有子查询的promise数组 const childQueryTasks = rst_parent.map(async (parentItem) => { const parent_name = parentItem.category_slug; arrStoreParentData.push(parent_name); // 执行子查询 const rst_child = await query(` SOME SQL QUERY { SECOND QUERY }=? `, [parent_name]); arrStoreChildData.push(rst_child); }); // 等待所有子查询全部执行完成 await Promise.all(childQueryTasks); // 所有查询完成后再返回结果 return res.send({ arrStoreChildData }); } catch (err) { console.log(err); return res.send({ msg: err }); } }
方案二:回调兼容写法
如果不想改动原有回调逻辑,可以手动统计子查询完成数量,全部完成后再返回响应:
let categoryget = (req,res)=>{ //get live category Data let arrStoreParentData = new Array(); //store parent id let arrStoreChildData = new Array(); // arr-store all category connection.query(` SOME SQL QUERY { FIRST QUERY } ='none'`, (err_parent,rst_parent)=>{ if(err_parent){ console.log(err_parent); return res.send({msg:err_parent}); }else{ // 统计子查询总数和已完成数量 const totalChildCount = rst_parent.length; let finishedChildCount = 0; //loop for getting the data //for parent for(var x=0; x < rst_parent.length ; x++){ let parent_name = rst_parent[x].category_slug; arrStoreParentData.push(parent_name); loopchild(parent_name); } function loopchild(zz){ connection.query(` SOME SQL QUERY { SECOND QUERY }=? `, [zz],(err_child,rst_child)=>{ if(err_child){ console.log(err_child); return res.send({msg:err_child}); }else{ let child_data = rst_child; arrStoreChildData.push(child_data); finishedChildCount++; // 所有子查询都执行完成后再返回 if(finishedChildCount === totalChildCount) { return res.send({arrStoreChildData}); } } }); } } }); }
内容的提问来源于stack exchange,提问作者manas singh
相关产品推荐
相关产品推荐

