与 bluebird 和 co 一起快速生成生成器功能
Generator functions in express with bluebird and co
我正在尝试节点 0.12 中的一些和谐功能,特别是尝试新的生成器功能。我正在使用 co (v4)、bluebird 和 express (v4) 执行此操作,如下所示:
// ...
var fs = bluebird.promisifyAll(require('fs'));
// ...
app.post('/test', co.wrap(function* (req, res, next) {
var contents = yield fs.readFileAsync('/etc/hosts', 'utf8');
return res.send(contents);
}));
// ...
根据其文档,co.wrap returns 一个普通函数,returns 来自给定生成器函数的承诺。
到目前为止一切正常,但我不确定是否 a) 我不是 'waiting' 为返回的 promise 的结果泄漏内存,以及 b) 如果我可能丢失抛出的异常在我的生成器函数中,或者它使用的模块之一。
这是一个好方法吗?你看有什么问题吗?
你的方法的问题是如果你的生成器函数会抛出一些异常,它不会被传递给下一个中间件。所以你会失去它。您可以使用 bluebird 的 Promise.coroutine
函数来实现您自己的简单 co
包装器,它将在 express 中运行良好:
// module: ../helpers/co.js
var Promise = require('bluebird');
var co = Promise.coroutine;
module.exports = function(gen) {
var coGen = co(gen);
function handle_error(err, req, res, next) {
return coGen.apply(this, arguments).catch(next);
}
function handle_request(req, res, next) {
return coGen.apply(this, arguments).catch(next);
}
return gen.length > 3 ? handle_error : handle_request;
};
UPD: 我对实现做了一点改动。现在它考虑了传递给生成器的数字或参数:如果 > 3 则将使用错误处理程序,否则 - 请求处理程序。对express很重要(看源码here and here)
现在您可以在代码中使用它了:
// module: your/router.js
// ...
var co = require('../helpers/co');
var fs = bluebird.promisifyAll(require('fs'));
// ...
app.post('/test', co(function* (req, res, next) {
var contents = yield fs.readFileAsync('/etc/hosts', 'utf8');
return res.send(contents);
}));
// ...
UPD 这是 express 版本 <= 4.x 的解决方案。最有可能表达 5.x will support promises,因此您可以只使用 bluebird 的 Promis.coroutine
而无需任何花哨的包装器:
// module: your/router.js
// ...
var fs = bluebird.promisifyAll(require('fs'));
var co = bluebird.coroutine;
// ...
app.post('/test', co(function*(req, res, next) {
var contents = yield fs.readFileAsync('/etc/hosts', 'utf8');
return res.send(contents);
}));
// ...
我正在尝试节点 0.12 中的一些和谐功能,特别是尝试新的生成器功能。我正在使用 co (v4)、bluebird 和 express (v4) 执行此操作,如下所示:
// ...
var fs = bluebird.promisifyAll(require('fs'));
// ...
app.post('/test', co.wrap(function* (req, res, next) {
var contents = yield fs.readFileAsync('/etc/hosts', 'utf8');
return res.send(contents);
}));
// ...
根据其文档,co.wrap returns 一个普通函数,returns 来自给定生成器函数的承诺。
到目前为止一切正常,但我不确定是否 a) 我不是 'waiting' 为返回的 promise 的结果泄漏内存,以及 b) 如果我可能丢失抛出的异常在我的生成器函数中,或者它使用的模块之一。
这是一个好方法吗?你看有什么问题吗?
你的方法的问题是如果你的生成器函数会抛出一些异常,它不会被传递给下一个中间件。所以你会失去它。您可以使用 bluebird 的 Promise.coroutine
函数来实现您自己的简单 co
包装器,它将在 express 中运行良好:
// module: ../helpers/co.js
var Promise = require('bluebird');
var co = Promise.coroutine;
module.exports = function(gen) {
var coGen = co(gen);
function handle_error(err, req, res, next) {
return coGen.apply(this, arguments).catch(next);
}
function handle_request(req, res, next) {
return coGen.apply(this, arguments).catch(next);
}
return gen.length > 3 ? handle_error : handle_request;
};
UPD: 我对实现做了一点改动。现在它考虑了传递给生成器的数字或参数:如果 > 3 则将使用错误处理程序,否则 - 请求处理程序。对express很重要(看源码here and here)
现在您可以在代码中使用它了:
// module: your/router.js
// ...
var co = require('../helpers/co');
var fs = bluebird.promisifyAll(require('fs'));
// ...
app.post('/test', co(function* (req, res, next) {
var contents = yield fs.readFileAsync('/etc/hosts', 'utf8');
return res.send(contents);
}));
// ...
UPD 这是 express 版本 <= 4.x 的解决方案。最有可能表达 5.x will support promises,因此您可以只使用 bluebird 的 Promis.coroutine
而无需任何花哨的包装器:
// module: your/router.js
// ...
var fs = bluebird.promisifyAll(require('fs'));
var co = bluebird.coroutine;
// ...
app.post('/test', co(function*(req, res, next) {
var contents = yield fs.readFileAsync('/etc/hosts', 'utf8');
return res.send(contents);
}));
// ...