我很确定我的问题与使用Koa或SQLite3没有直接关系,但更多的是与JavaScript的一般用法有关。
我有以下server.js
:
var http = require('http');
var koa = require('koa');
var route = require('koa-route');
var app = koa();
var sqlite3 = require('sqlite3').verbose();
var dbFile = 'coc.db';
var db = new sqlite3.Database(dbFile);
var members = [];
var printMembers = function(name){
db.each(query, [name], function(err, row){
members.push(row);
});
return members;
}
app.use(route.get('/', index));
function *index() {
this.body = printMembers("name");
}
app.listen(8008);
console.log('Koa listening on port 8008');
当我第一次启动服务器并访问localhost:8008
时,我只得到一个空数组([]
)作为响应。这是变量members
的内容。当我重新加载时,我按预期得到了我的SQLite查询结果。
原因可能是因为我的查询花费的时间比执行脚本的时间长。当然,第二次填充members
。但是第一次查询的结果!
另外var members = []
应在printMembers
内声明。
在我看来,我需要确定一些事情,index()
等待db.each()
完成。但是我怎么能实现这个目标呢?
答案 0 :(得分:3)
由于Koa 1.x中的核心抽象是使用生成器来控制流
在路线中,您必须使用yield
等待某些事情完成。
Koa在引擎盖下使用https://github.com/tj/co,所以在尝试时
作为Koa开发人员,您可以与为Koa构建的库互操作
基本上只需要弄清楚如何修改/包装异步库
这样你就可以在你的路线中yield
。
你基本上可以yield
生成器和承诺。
这项工作最通用的工具是用函数包装函数
一个承诺。创建承诺(new Promise(fn)
)时,您必须传递它
函数fn
,它将两个函数作为参数:resolve
和reject
。
你经常可以找到Co-specific库,其中有人已经包装了一个流行的
库以一种允许yield
其功能/方法的方式。
例如,请查看https://www.npmjs.com/package/co-sqlite3。 (我不知道它有多好,但幸运的是,如果事实证明这是不好的话,你自己很容易把它包起来)
或者,有些库可以采用回调式模块(即大多数Node模块)
并将其包装,以便它返回你可以yield
的承诺。
例如,bluebird有一个promisifyAll功能可以做到这一点,但说实话,我从未使用过蓝鸟。
// (Untested)
var Promise = require('bluebird');
var sqlite3 = require('sqlite3').verbose();
var db = Promise.promisifyAll(new sqlite3.Database(':memory:'));
function* printMembers(name) {
var query = '...';
return yield db.allAsync(query, [name]);
}
function* index() {
// promisifyAll adds an {fnName}Async version of all the functions
// to the module you call it on, so now we can call `allAsync`.
var members = yield db.allAsync(query, ['name']);
// or
var members = yield printMembers('name');
this.body = members;
}
但我会给你一些承诺包装的例子,因为它是如此重要 工具箱中有工具。
在这里,我重写你的printMembers
函数以返回你的Promise
然后可以从您的路线yield
:
var printMembers = function(name) {
var query = '...';
return new Promise(function(resolve, reject) {
var rows = [];
db.each(query, [name], function(err, row){
if (err) return reject(err);
rows.push(row);
});
resolve(rows);
});
}
虽然注意sqlite3有一个Database#all 函数会一次性返回所有行,因此您不必手动构建数组:
var printMembers = function(name) {
var query = '...';
return new Promise(function(resolve, reject) {
db.all(query, [name], function(err, rows){
if (err) return reject(err);
resolve(rows);
});
});
}
现在,您的路线如下:
function *index() {
var members = yield printMembers('name');
this.body = members;
}
如果承诺到达reject(err)
路径,那么承诺将被拒绝
状态并抛出你可以尝试/捕获的错误,如果你想要你屈服的地方
承诺。
如果承诺到达resolve(members)
路径,那么那就是产生了什么
并分配给members
变量。