Generator functions in express with bluebird and co

喜夏-厌秋 提交于 2019-12-21 09:39:10

问题


I'm trying out some of the harmony features in node 0.12, in particular trying out the new generators feature. I'm doing this with co (v4), bluebird and express (v4), something like this:

 // ...
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);
}));
// ...

According to its documentation, co.wrap returns a normal function that returns a promise from the given generator function.

This is working fine so far, but what I'm not sure is if a) I'm leaking memory by not 'waiting' for the returned promise's result and b) If I might lose an exception thrown in my generator function, or one of the modules used by it.

Is this a good approach? Do you see anything wrong with it?.


回答1:


The problem with your approach is that if your generator function will throw some exception, it will not be passed to next middleware. So you will lose it. You can use bluebird's Promise.coroutine function to implement your own simple co wrapper, which will be working well in 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: I have changed the realization a little. Now it takes into account the number or arguments passed into the generator: if > 3 then error handler will be used, otherwise - request handler. It's important for express (look in the source code here and here)

Now you can use it in your code:

// 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 This is solution for express with version <= 4.x. Most likely express 5.x will support promises, so you'll can use just bluebird's Promis.coroutine without any fancy wrappers:

// 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);
}));
// ...


来源:https://stackoverflow.com/questions/29186246/generator-functions-in-express-with-bluebird-and-co

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!