Node.js使用sqlite3时db.get返回Database对象及异步取值异常问题
问题根源
- 你遇到的所有异常都来自
sqlite3的API默认是异步非阻塞设计:db.get()执行后不会等待数据库查询完成,会直接返回Database实例本身(也就是你最开始拿到的Database {}对象),查询结果只会通过回调函数返回,你最初给uname赋值的其实是这个db实例,不是查询结果- JS执行同步代码优先级高于异步回调,所以
db.get()外部的console.log和return逻辑会先执行,此时回调还没触发,uname自然是undefined,等回调执行给uname赋值的时候,你的函数早就已经返回结果了,赋值完全没用
解决方案:用Promise封装异步查询,配合async/await使用
第一步:修改registrant_existence.js,把函数改成返回Promise
// necessary requirements and initialisation function registrant_existence(username) { return new Promise((resolve, reject) => { const sql = 'SELECT username FROM table WHERE username=?'; db.get(sql, username, function(err, row) { if (err) { return reject(err); } // row存在说明用户名已被占用 if (row) { resolve({username: 'Username already in use.'}); } else { resolve('DNE'); } }); }); }; module.exports = registrant_existence;
第二步:修改register.js的路由逻辑,用async/await等待异步结果
let registrant_existence = require("path to registrant_existence.js"); // necessary requirements and initialisation // 给路由回调加async关键字 router.post('/', async function(req, res) { try { // 用await等待异步查询的结果 let existence = await registrant_existence(req.body.username, req.body.email); if (existence != 'DNE') { // render registration page notifying the user // that the username is already in use } else { // register the new user details } } catch (err) { // 处理数据库查询抛出的错误 console.error(err); res.status(500).send('服务器内部错误'); } });
补充说明
如果需要同时校验邮箱是否存在,可以修改SQL语句同时查询两个条件,或者并行发起两个查询用Promise.all处理,逻辑更简洁。也可以直接使用sqlite包(是sqlite3的官方Promise封装版本),不用自己手动封装Promise,直接支持await调用db.get方法。
内容的提问来源于stack exchange,提问作者Zeta-Squared
相关产品推荐
相关产品推荐

