Node.js异步函数内SQLite请求的异步处理与结果返回问题
解决SQLite异步查询导致返回空数组的问题
你碰到的问题本质是没抓住SQLite each()方法的异步特性——它会立刻返回,然后在后台逐步处理查询结果,而你的代码在结果还没遍历完的时候就急着返回数组了,自然拿到的是空值。下面针对你给出的两种方案分别修正,帮你理解怎么正确等待异步操作完成。
修正Promise方案
原来的代码里,你在each()调用后直接resolve(array),但这时候each()还没开始遍历结果呢!我们要利用each()的第三个参数——完成回调,这个回调会在所有行都处理完毕后触发,这时候才是resolve数组的正确时机。
修正后的dbHandler.js代码
var Promise = require("bluebird"); getList: function(userID) { return new Promise(function(resolve, reject) { var array = []; sql.each( `SELECT * FROM table WHERE userID = ?`, userID, // 每一行的处理回调 (err, row) => { if (err) { // 遇到错误直接reject,终止后续处理 return reject(err); } console.log("row: " + row + " element: " + row.username); array.push(row); }, // 所有行处理完成的回调 function(err, count) { if (err) { return reject(err); } // 现在数组已经被完全填充了 console.log("array: " + JSON.stringify(array)); resolve(array); } ); }); }
修正后的list.js调用代码
db.getList(uid) .then(function(v) { // 注意:数组的长度是length,不是size! console.log("size: " + v.length); // 可以遍历验证结果 v.forEach(element => console.log("element: " + element.username)); }) .catch(function(err) { console.log("failed: " + err); });
修正回调方案
回调方案的问题和Promise版本一样:你在each()还没处理完结果时就调用了自定义回调,这时候数组还是空的。同样要借助each()的完成回调来触发我们的自定义回调。
修正后的dbHandler.js代码
getList: function(userID, callback) { var array = []; sql.each( `SELECT * FROM warns WHERE userID = ?`, userID, // 每一行的处理回调 (err, row) => { if (err) { // 出错时直接返回错误给回调 return callback(err, null); } array.push(row); }, // 所有行处理完成的回调 function(err, count) { if (err) { return callback(err, null); } // 数组填充完毕,返回给调用方 callback(null, array); } ); },
修正后的list.js调用代码
db.getList(uid, function (err, response) { if (err) { console.log("Error:", err); } else { // 同样用length获取数组长度 console.log("size: " + response.length); response.forEach(element => console.log("element: " + element.username)); } });
关键要点总结
- 等待异步操作完成:SQLite的
each()是异步的,必须等到它的完成回调触发,才能确保所有结果都被加入数组。 - 正确处理错误:不管是Promise的
reject还是回调的错误参数,都要把错误传递出去,而不是只打印在控制台。 - 数组属性小细节:数组的长度属性是
length,不是size,这是你之前输出undefined的另一个原因。
内容的提问来源于stack exchange,提问作者omnomnom
相关产品推荐
相关产品推荐

