先看koa怎么搞?
这个好办, 下面是一个简单的router(路由web API)。
我们看到在router.get 第二个参数加了async关键字修饰的方法。
根据ES6,我们知道async函数内可以使用await强制等待异步Promise函数的相应结果。
很明显,上面的runSql函数返回不是一个Promise对象的,所以这里先调用一个未实现的函数:prunSql。
router.get('/asynQuery', async function(ctx, next){ //参考上面Promise使用,声明同步等待一个返回Promise对象的函数。 var data = await prunSql('SELECT * FROM COMPANY;'); ctx.body = JSON.stringify(data) });
这是一个新的接口, 跟其他接口不一样的就是,它处理请求的方法是用async声明的异步函数。
我们需要改造runSql函数
const prunSql = function(sql){ console.log('will run sql:', sql); return new Promise(function(resolve, reject){ console.log('asyn run sql: ', sql); db.query(sql, function(error, result, fields){ if(error){ console.log('[%s] asyn error:', error); reject(error); }else{ console.log('asyn result:', result); resolve(result); } }); }); };
这就是改造好的prunSql,这里用了resolve函数把数据库查询结果传递出去。
这样在使用Promise的then可以获取到异步查询结果。
或者在一个异步响应的方法内await Promise对象,等待查询返回值。
看看使用Promise处理后的效果:
问题至此,迎刃而解!
具体用什么框架做接口不重要,理解整个思想才是重点。
贴一下代码, 下面的数据库查询库(db-lite.js),读者可自行更换成其他异步查询的库,进行改造,不必过多纠结一定要使用本文的runSql函数。
const koa = require('Koa'); const app = new koa() var router = require('koa-router')(); var db = require('./db-lite'); router.get('/', function(ctx, next){ctx.body='Hello, geeklevin!'}); router.get('/query', function(ctx,next){ db.runSql("SELECT * FROM COMPANY; ", function(result,fields){ console.log('查询结果:', result); ctx.body = JSON.stringify(result); console.log('设置响应body成功!'); }); console.log('processing'); }); router.get('/asynQuery', async function(ctx, next){ var data = await db.prunSql('SELECT * FROM COMPANY;'); ctx.body = JSON.stringify(data) }); app.use(router.routes()); const PORT = 8081 console.log('start app at port %s', PORT) app.listen(PORT);
db-lite.js 代码:
const mysql = require('mysql'); const db = mysql.createConnection({ host: "localhost", port: 3306, user: "root", password: "12345678" }); const logDbStat = function(){ console.log("db state %s and threadID %s", db.state, db.threadId); // console.log("db detail:", db); } logDbStat(); console.log('start to connect mysql'); db.connect(function(err){ if(err){ console.log('fail to connect db',err.stack); throw err; } logDbStat(); }); const close = function(){ db.destroy(); console.log('db disconnected'); logDbStat(); }; var counter = 0; const runSql = function(sql, callback){ counter++; var cv = counter; console.log('run sql[%s] :[%s]',cv, sql); db.query(sql, function(error, result, fields){ try{ if(error) throw error; }finally{ if(callback) callback(result, fields); } }); } const prunSql = function(sql){ console.log('will sql:', sql); return new Promise(function(resolve, reject){ counter++; var cv = counter; console.log('asyn run sql[%s] :[%s]', cv, sql); db.query(sql, function(error, result, fields){ if(error){ console.log('[%s] asyn error:', cv, error); reject(error); }else{ // console.log('[%s] asyn result:', cv, result); resolve(result); } }); }); }; const myDb = 'demo20210330'; runSql("USE " + myDb); module.exports.runSql = runSql; module.exports.prunSql = prunSql;
总结
Promise结合async和await结合能够产生神奇的效果,也是很多新手过不去的坎,希望读者都能够熟练运用。
上面展示代码,读者可以自行思考,改造工作中使用的异步请求转化为同步调用。
篇幅有限,当然这本质上还是异步执行的,希望读者自行鞭策,思考理解。