Node.js读取SQLite数据存入数组 外部访问输出undefined
问题原因
sqlite3 提供的数据库操作接口全是异步非阻塞的,调用db.all时不会等待查询完成再执行后续代码,而是先把回调函数暂存,等数据库返回结果后才会执行回调。
你当前代码的执行顺序:
- 先声明7个空数组,创建数据库连接,发起查询请求
- 立刻执行回调外的
console.log,此时查询还没完成,回调还没触发,数组还没被写入任何数据,你访问数组元素时自然会拿到undefined - 查询完成后回调才会执行,往数组里push数据,但此时打印逻辑早就执行完了。
修复方案
方案1:直接在回调内处理查询结果
所有依赖查询结果的逻辑,全部放到db.all的回调内部,等数据填充完成后再执行:
let hostnames = []; let usernames = []; let passwords = []; let commands = []; let status = []; let ids = []; let mac = []; const sqlite3 = require('sqlite3').verbose(); const db = new sqlite3.Database('../database/database.sqlite',(err)=>{ if(err){ return console.error(err.message); } console.log('Connected...'); }); db.all('SELECT * FROM Users ORDER BY id',[],(err,rows)=>{ if(err){ return console.error(err.message); } rows.forEach((row)=>{ hostnames.push(row.name); usernames.push(row.username); passwords.push(row.password); commands.push(row.command); status.push(row.status); mac.push(row.mac); ids.push(row.id); }); // 数据填充完成后再操作数组 console.log("hostnames",hostnames); // 其余依赖这些数组的逻辑全部写在这里 });
方案2:Promise封装+async/await(推荐,避免回调嵌套)
把异步接口包装成Promise,用async/await写法让逻辑更线性,避免多层回调嵌套:
const sqlite3 = require('sqlite3').verbose(); const db = new sqlite3.Database('../database/database.sqlite',(err)=>{ if(err){ return console.error(err.message); } console.log('Connected...'); }); // 封装db.all为Promise接口 function dbQuery(sql, params = []) { return new Promise((resolve, reject) => { db.all(sql, params, (err, rows) => { if (err) reject(err); resolve(rows); }); }); } async function loadUserData() { const hostnames = []; const usernames = []; const passwords = []; const commands = []; const status = []; const ids = []; const mac = []; const rows = await dbQuery('SELECT * FROM Users ORDER BY id'); rows.forEach((row)=>{ hostnames.push(row.name); usernames.push(row.username); passwords.push(row.password); commands.push(row.command); status.push(row.status); mac.push(row.mac); ids.push(row.id); }); return {hostnames, usernames, passwords, commands, status, ids, mac}; } // 调用加载函数,拿到数据后再做后续处理 loadUserData().then(userData => { console.log('hostnames', userData.hostnames); // 其余业务逻辑写在这里 }).catch(err => { console.error(err.message); });
注意:JavaScript事件循环机制决定了你无法通过同步写法在异步回调外部直接拿到异步操作的结果,所有依赖异步返回值的逻辑都必须在回调内、Promise的then链或者await之后执行。
内容的提问来源于stack exchange,提问作者Didem
相关产品推荐
相关产品推荐

