2015-03-21 10 views
8

Sto provando alcune delle funzionalità di armonia nel nodo 0.12, in particolare provando la nuova funzione di generatori. Sto facendo questo con il co (v4), Bluebird ed esprimere (v4), qualcosa di simile:Funzioni generatore in express con bluebird e 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); 
})); 
// ... 

Secondo la documentazione, co.wrap restituisce una normale funzione che restituisce una promessa dalla data funzione del generatore .

Questo sta lavorando bene finora, ma quello che non sono sicuro è che se a) sto perdite di memoria non e 'in attesa' per il risultato della promessa restituiti e b) Se potrei perdere un'eccezione gettato nel mio generatore funzione, o uno dei moduli utilizzati da esso.

È un buon approccio? Vedi qualcosa di sbagliato?

+0

Vuol 'app.post' si aspettano di attendere il risultato asincrona della vostra richiamata in qualche modo? – Bergi

+0

app.post è express 'app.post. Quindi, suppongo di no (?) – Matt

+2

È inutile usare 'co' se si sta usando bluebird dato che bluebird viene fornito con' Promise.coroutine' che è comunque una versione più potente e robusta di 'co'. –

risposta

10

Il problema con il vostro approccio è che se la vostra funzione generatore genererà qualche eccezione, non sarà passata al middleware successivo. Quindi lo perderai. È possibile utilizzare la funzione di Bluebird Promise.coroutine per implementare il proprio semplice co involucro, che sarà lavorando bene in veloce:

// 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: ho cambiato la realizzazione un po '. Ora prende in considerazione il numero o gli argomenti passati nel generatore: se> 3 verrà utilizzato il gestore degli errori, altrimenti - gestore della richiesta. E 'importante per espresso (guarda nel codice sorgente here e here)

Ora è possibile utilizzarlo nel codice:

// 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 Questa è la soluzione per espresso con la versione < = 4.x. Molto probabilmente esprimere 5.x will support promises, quindi dovrete possibile utilizzare solo di Promis.coroutine Bluebird senza wrapper fantasia:

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

In generale, il secondo approccio è molto meglio del primo poiché chiama solo Promise.coroutine una volta: "Promise.coroutine" viene chiamato solo in fase di inizializzazione. –

+0

@BenjaminGruenbaum In realtà, in entrambi gli approcci veniva chiamato 'Promise.coroutine' su ogni richiesta. Ora chiama solo una volta. Grazie per il commento! Inoltre ho aggiunto commenti sulle versioni future di Express. – alexpods