JS使用sqlite3模块时await无法等待.get()查询结果问题
问题根源
sqlite3 原生提供的是回调风格API,这类API不会返回Promise对象,而await关键字仅对Promise/符合Promise A+规范的thenable对象生效,因此你直接在.get()调用前加await不会等待查询执行完成。代码会直接向下运行,此时查询完成的回调还没触发,prefix变量未被赋值,自然返回undefined。
额外提醒:你当前直接拼接message.guild.id到SQL语句的写法存在SQL注入风险,即便是Discord的雪花ID,也建议统一用参数化查询传参。另外你把机器人消息判断放在了查询之后,会产生大量无意义的数据库请求,浪费性能。
修复方法
方法1:手动包装为Promise(兼容所有sqlite3版本)
将查询逻辑包裹在Promise中,在回调内部处理查询成功/失败的状态,即可正常使用await等待结果返回,修复后的完整代码如下:
module.exports = { name: "messageCreate", once: false, async execute(client, message) { // 提前拦截机器人消息,减少不必要的数据库查询 if (message.author.bot) return; // 包装查询为Promise const prefix = await new Promise((resolve, reject) => { client.db.get( // 用?做参数占位符,走参数化查询 `SELECT prefix FROM "Guilds" WHERE id = ?`, [message.guild.id], (err, row) => { if (err) return reject(err); // 加默认前缀兜底,避免无配置时row为undefined报错 resolve(row?.prefix ?? "!"); } ); }); if (!message.content.startsWith(prefix)) return; const args = message.content.slice(prefix.length).trim().split(/ +/g); const cmdName = args.shift().toLowerCase(); if (cmdName.length === 0) return; const cmd = client.commands.get(cmdName); cmd?.run(client, message, args); }, };
方法2:用Node内置工具快速转Promise风格
如果你不想每次写查询都手动包Promise,可以在初始化数据库连接的位置,用Node内置util模块的promisify方法,把回调风格的get方法转换为Promise风格:
// 数据库初始化文件中添加 const { promisify } = require("util"); // 注意要绑定db上下文,避免调用时this指向错误 client.db.get = promisify(client.db.get.bind(client.db));
转换完成后,后续所有调用client.db.get()的位置只要不传回调参数,就会直接返回Promise,可以直接用await接收结果:
// 事件中直接使用即可 const row = await client.db.get(`SELECT prefix FROM "Guilds" WHERE id = ?`, [message.guild.id]); const prefix = row?.prefix ?? "!";
内容的提问来源于stack exchange,提问作者Zitta
相关产品推荐
相关产品推荐

