(更新:这些天你会使用 Koa 2.x,它使用 Promise 和一流的 async/await 来代替这个答案中的 co/yield 示例。)
由于 Koa 1.x 中的核心抽象是使用生成器来控制流
在路由中,您必须使用yield 等待某事完成。
Koa 在后台使用https://github.com/tj/co,所以当你尝试
与不是为 Koa 构建的库互操作,作为 Koa 开发人员,您
基本上只需要弄清楚如何修改/包装异步库
这样您就可以在您的路线内yield 他们。
您基本上可以yield 生成器和承诺。
这项工作最通用的工具是用
一个承诺。创建 Promise (new Promise(fn)) 时,必须将其传递给
函数 fn 接受两个函数作为参数:resolve 和 reject。
你经常可以找到一些特定的库,其中有人已经包装了一个流行的
库,让您yield 其功能/方法。
例如,查看https://www.npmjs.com/package/co-sqlite3。 (我不知道它有多好,但幸运的是,如果结果不好,你自己包装东西很容易)
或者,有些库可以采用回调样式模块(即大多数 Node 模块)
并包装它,以便它返回您可以yield 的承诺。
例如,bluebird 有一个 promisifyAll 函数可以做到这一点,但老实说我从未使用过 bluebird。
// (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;
}
但我会给你一些 Promise 包装的例子,因为它是如此重要
工具包中的工具。
在这里,我重写了您的 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;
}
如果 Promise 命中 reject(err) 路径,则 Promise 将被放入拒绝
状态并抛出错误,如果你想在哪里产生,你可以尝试/捕获
承诺。
如果承诺命中resolve(members) 路径,那么这就是产生的结果
并分配给members 变量。