2015-03-21 7 views
8

Ich probiere einige der Harmonie-Funktionen in Knoten 0.12, insbesondere das Ausprobieren der neuen Generatoren Feature. Ich tue dies mit Co (v4), drossel und Express (v4), etwa so:Generator-Funktionen in Express mit Bluebird und Co

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

Nach seiner Dokumentation, kehrt co.wrap eine normale Funktion, die ein Versprechen von der gegebenen Generatorfunktion zurückgibt .

Das funktioniert soweit, aber was ich nicht sicher bin, ist a) Ich lecke Speicher, indem ich nicht auf das Ergebnis des zurückgegebenen Versprechens "warte" und b) Wenn ich eine Ausnahme in meinem Generator verlieren könnte Funktion oder eines der von ihm verwendeten Module.

Ist das ein guter Ansatz? Siehst du irgendwas falsch damit?

+0

Hat 'app.post' erwarten, dass das asynchrone Ergebnis Ihres Rückruf warten? – Bergi

+0

app.post ist express 'app.post. Also, ich nehme an, es ist nicht (?) – Matt

+2

Es ist sinnlos, 'co' zu verwenden, wenn du bluebird verwendest, da bluebird mit' Promise.coroutine' ausgeliefert wird, welches sowieso eine leistungsfähigere und robustere Version von 'co' ist. –

Antwort

10

Das Problem mit Ihrem Ansatz ist, dass wenn Ihre Generator-Funktion eine Ausnahme auslöst, wird es nicht an die nächste Middleware weitergegeben. So wirst du es verlieren. Sie können Promise.coroutine Funktion des drossel verwenden, um Ihre eigenen einfachen co Wrapper zu implementieren, die auch in Express arbeiten werden:

// 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: Ich geändert haben die Realisierung ein wenig. Jetzt berücksichtigt es die Anzahl oder Argumente, die an den Generator übergeben werden: Wenn> 3, dann wird der Fehlerbehandler verwendet, ansonsten - Anforderungshandler. Es ist wichtig, für Express (Blick in den Quellcode here und here)

Jetzt können Sie es in Ihrem Code verwenden:

// 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 Diese Lösung mit Version < = 4.x. für Express ist Wahrscheinlich ausdrücken 5.x will support promises, so dass Sie nur Promis.coroutine Bluebird verwenden können, werden ohne Phantasie-Wrapper: irgendwie

// 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

Im Allgemeinen - der zweite Ansatz ist viel besser als Ihr erster, da es nur "Promise.coroutine" einmal aufruft - "Promise.coroutine" soll nur in der Initialisierungszeit aufgerufen werden. –

+0

@BenjaminGruenbaum Eigentlich nannte es bei beiden Ansätzen 'Promise.coroutine' bei jeder Anfrage. Jetzt ruft es nur einmal an. Danke für den Kommentar! Auch habe ich Bemerkung über zukünftige Versionen von Eil hinzugefügt. – alexpods