Node.js中while循环代码非顺序执行,无法修改flag值问题
问题根源:异步操作的事件循环机制
你遇到的问题核心是Node.js里的数据库查询是异步非阻塞操作,而你的while循环是同步执行的,两者的执行顺序完全不符合你的预期。
为什么代码顺序不对?
JavaScript的事件循环会先执行所有同步代码:
- 初始化
flag=0,进入while(!flag)循环 - 每次循环里调用
connection.query,这个操作是异步的——它会立即返回,把查询任务放到后台执行,不会阻塞后续代码 - 紧接着执行
console.log('flag value : '+flag),这时候回调函数还没触发,flag还是初始值0 offset++,然后继续下一轮循环,直到同步代码的循环跑了N次之后,后台的数据库查询才完成,触发回调函数去修改flag——但这时候循环可能已经跑了无数次,而且flag的修改已经没法阻止之前的循环执行了
这就是为什么你看到console.log先输出,且flag一直不变的原因。
解决方案:用异步方式替代同步while循环
不能用同步的while来等待异步操作,我们可以用async/await配合Promise来实现你想要的逻辑,让代码按预期顺序执行:
第一步:把数据库查询封装成Promise
先把两个查询改成返回Promise的函数,这样就能用await来等待结果:
// 封装第一个查询:获取符合条件的买单 function getBuyOrder(coinId, offset) { return new Promise((resolve, reject) => { // 注意用参数化查询避免SQL注入! const sql = 'SELECT nlc,id,user_id FROM tbl_buy WHERE `type`="buy" AND `status`="available" AND coin_id=? AND order_type="market" ORDER BY id ASC LIMIT ?,1'; connection.query(sql, [coinId, offset], (error, results) => { if (error) return reject(error); resolve(results); }); }); } // 封装第二个查询:获取对应的卖单 function getSellOrders(buyUserId, coinId, buyNlc) { return new Promise((resolve, reject) => { const sql = `SELECT tbl_buy.* from ( select tbl_buy.*, (@sum := @sum + nlc) as cume_stock from tbl_buy cross join (select @sum := 0) params WHERE tbl_buy.type="sell" AND tbl_buy.status="available" AND tbl_buy.user_id!=? AND tbl_buy.coin_id=? AND tbl_buy.order_type="market" ORDER BY id ) tbl_buy where cume_stock-nlc < ?`; connection.query(sql, [buyUserId, coinId, buyNlc], (error, results_arr) => { if (error) return reject(error); resolve(results_arr); }); }); }
第二步:用async函数实现逻辑
用async/await来替代同步while,让代码按顺序执行:
async function processMarketOrders(jsondata) { let offset = 0; while (true) { // 等待第一个查询完成 const buyResults = await getBuyOrder(jsondata.coinid, offset); if (buyResults.length === 0) { // 没有找到符合条件的买单,退出循环 break; } // 找到买单后,执行第二个查询 const sellResults = await getSellOrders(buyResults[0].user_id, jsondata.coinid, buyResults[0].nlc); // 返回结果并触发回调 res.end(JSON.stringify(sellResults)); myCallback(buyResults, sellResults); // 如果只需要处理第一个找到的订单,就break;如果要继续遍历,就去掉break并offset++ break; // offset++; } } // 调用函数,记得处理错误 processMarketOrders(jsondata) .catch(err => { console.error('处理订单出错:', err); res.status(500).end('服务器内部错误'); });
额外提醒:SQL注入风险
你原来的代码直接把jsondata.coinid、results[0].user_id等变量拼到SQL语句里,这存在严重的SQL注入风险!上面的解决方案里已经用了参数化查询(?占位符+参数数组),一定要坚持这种写法,避免安全问题。
内容的提问来源于stack exchange,提问作者bhayashree
相关产品推荐
相关产品推荐

