Поскольку основная абстракция в Koa 1.x заключается в использовании генераторов для потока управления в маршрутах, вы должны использовать yield
, чтобы подождать, пока что-то закончится.
Коа использует https://github.com/tj/co под капотом, поэтому при попытке Interop с библиотеками, которые не построены для Коа, как разработчик Коа вы в основном просто нужно выяснить, как вы можете изменить/завернуть асинхронные библиотеки так, что вы можете yield
их внутри вашего маршрута.
Вы можете в основном yield
генераторы и обещания.
Наиболее универсальным инструментом для работы является обертывание функции с помощью a Promise. При создании Promise (new Promise(fn)
) вы должны передать ему функцию fn
, которая принимает две функции в качестве аргументов: resolve
и reject
.
Вы можете часто находить библиотеки со спецификой, в которых кто-то уже обернул популярную библиотеку таким образом, чтобы вы могли использовать ее функции/методы yield
.
Например, https://www.npmjs.com/package/co-sqlite3. (Я понятия не имею, насколько это хорошо, но, к счастью, легко обернуть материал, если он окажется не лучшим)
В качестве альтернативы существуют библиотеки, которые могут использовать модуль обратного вызова (то есть большинство модулей узла) и оберните его, чтобы он дал обещания, которые вы можете 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
функцию, чтобы вернуть обещание, которое вы можете 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
.
Вау, это был прекрасный ответ! a) Теперь я знаю, какой lego кирпич JS я отсутствовал, b) вы дали несколько подходов к решению и c) вы даже дали рабочий пример. Спасибо огромное! Его просто сложно, когда у вас есть проблема, но не знаю, что искать! – cvoigt