Node.js中sqlite3的db.all()异步问题:如何串行更新全局变量
Node.js sqlite3 异步操作串行化解决方案
你的问题核心是没搞懂Node.js的异步非阻塞特性:db.all()是异步IO方法,调用它之后程序不会等待数据库查询完成,而是直接往下执行db.close()和console.log("x = ", x),等数据库查询结果返回后才会执行回调函数里的逻辑,所以才会出现打印顺序颠倒的情况。
下面是两种解决方法:
方法1:将后续逻辑放入回调函数内
把需要等待查询完成后执行的操作(比如关闭数据库、打印最终的x)全部放到db.all()的回调函数里,确保顺序执行:
var sqlite3 = require('sqlite3').verbose(); var db = new sqlite3.Database('first.db'); console.log("in the program"); var x = []; console.log("x = ", x); console.log("db.all()"); db.all("SELECT * FROM coords", function(err, rows) { console.log("\nin db.all()"); for(var row of rows) { x.push(row.x); console.log(x); } // 所有操作完成后再关闭数据库、打印最终结果 console.log("x = ", x); db.close(); });
方法2:用Promise + async/await 实现类同步写法
如果觉得回调嵌套不够直观,可以把db.all()包装成Promise,再用async/await让异步代码看起来像同步执行:
var sqlite3 = require('sqlite3').verbose(); var db = new sqlite3.Database('first.db'); // 包装db.all为Promise function queryAll(sql) { return new Promise((resolve, reject) => { db.all(sql, (err, rows) => { if (err) reject(err); else resolve(rows); }); }); } // 用async函数执行异步逻辑 async function run() { console.log("in the program"); var x = []; console.log("x = ", x); console.log("db.all()"); try { const rows = await queryAll("SELECT * FROM coords"); console.log("\nin db.all()"); for(var row of rows) { x.push(row.x); console.log(x); } console.log("x = ", x); } catch(err) { console.error(err); } finally { db.close(); } } run();
补充说明:你提到的"并发"其实不准确,这里是Node.js的异步IO机制——当程序遇到耗时的IO操作(比如数据库查询)时,会把这个操作交给底层线程处理,主线程继续执行后续代码,等IO操作完成后再通知主线程执行回调,以此提升程序的整体效率。
内容的提问来源于stack exchange,提问作者dudung
相关产品推荐
相关产品推荐

