等待数据库查询完成
Wait until DB query is done
我很确定我的问题与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()
完成。但是我怎样才能做到这一点呢?
(更新:这些天你会使用 Koa 2.x,它使用承诺和一流的异步/等待来代替这个答案中的 co/yield 示例。
由于 Koa 1.x 中的核心抽象是使用生成器进行控制流在路由中,您必须使用 yield
等待某些内容完成。
Koa 在引擎盖下使用 https://github.com/tj/co,所以当尝试与不是为 Koa 构建的库互操作,作为 Koa 开发人员,您基本上只需要弄清楚如何修改/包装异步库以便您可以在路线内yield
它们。
你基本上可以yield
生成器和承诺。
该作业最通用的工具是将函数包装为a 承诺。创建承诺 ( new Promise(fn)
( 时,必须传递它函数fn
,它将两个函数作为参数:resolve
和 reject
。
您经常可以找到 Co 特定的库,其中有人已经包装了一个流行的库允许您yield
其函数/方法。
例如,签出 https://www.npmjs.com/package/co-sqlite3。(我不知道它有多好,但幸运的是,如果结果不好,很容易自己包装东西(
或者,有些库可以采用回调样式的模块(即大多数 Node 模块(并包装它,以便它返回您可以yield
的承诺。
有一个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
函数以返回您的承诺然后可以从您的路线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
变量。
- 在窗体中间单击按钮查询数据库
- Php菜单查询数据库并显示文本/链接
- Javascript 刷新查询数据库
- 在调用 ajax 和查询数据库时遇到问题
- ajax sql 和 PHP 查询数据库并返回结果
- 您如何确保在使用猫鼬时仅在我们完成连接后才查询数据库
- 查询数据库并在同一页面上显示结果
- Hexo:如何在插件中查询数据库
- Ajax和PHP:SELECT查询数据库
- 使用Ajax查询数据库
- ECONNRESET一行查询数据库两次写错误[Node.js]
- 查询数据库中的所有文档,而不是查询mongoose中的任何特定集合
- 如何通过javascript(或JQuery)点击查询数据库
- 图表不显示值/使用ajax绘制图表/如何通过查询数据库绘制图表
- 下拉菜单更改后查询数据库,然后输出到表单
- 如何查询数据库而不重新加载网页
- 为HTML超链接创建查询数据库的函数
- 如何使页面上的Javascript可以使用MSSQL查询数据,而无需再次查询数据库
- Sails.js通过外键查询数据库
- 直接从javascript查询数据库