2016-01-07 12 views
8

Si consideri un esempio: Ho la seguente app express.js (vedere lo snippet di codice di seguito). Voglio avere una connessione permanente al DB e una connessione permanente al mio servizio (che richiedeva la chiamata async per l'avvio) durante l'intera durata dell'app. E ci sono alcuni punti di accesso, ad esempio uno può accedere alla mia app non solo tramite il protocollo HTTP. Ovviamente, voglio evitare la duplicazione del codice di inizializzazione del servizio e potrebbero esserci diversi servizi di inizializzazione asincrona.Inizializzazione asincrona delle app express.js (o simili)

/* app.js */ 
var app = require('express')(); 
// set views, use routes, etc. 
var db = require('monk/mongoose/etc')(...); // happily, usually it's a sync operation 
var myService = require('./myService');  // however, it's possible to have several such services 
myService.init(function(err, result) { 
    // only here an initialization process is finished! 
}); 

module.exports.app = app; 


/* http_server.js (www entry point) */ 
var app = require('app'); 
// create an HTTP server with this app and start listening 


/* telnet_server.js (other entry point) */ 
var app = require('app'); 
// create a Telnet server with this app and start listening 

Nel frammento di codice di cui sopra, per il momento in http (o telnet, o qualsiasi altro) del server sta iniziando, non v'è alcuna garanzia, che myService già è stato inizializzato.

Quindi, devo in qualche modo riorganizzare il codice di creazione dell'app. Per il momento mi attengo alla soluzione successiva:

/* app.js */ 
var app = require('express')(); 
module.exports.app = app; 
module.exports.init = function(callback) { 
    var myService = require('./myService'); 
    myService.init(callback);  
} 

/* entry_point.js */ 
var app = require('app'); 
app.init(function(err) { 
    if (!err) { 
     // create an HTTP/Telnet/etc server and start listening 
    } 
}); 

Quindi, la mia domanda è: qual è il modo comune per inizializzare servizi richiesti chiamata asincrona per iniziare?

+0

In realtà non è diverso da come serializzi qualsiasi serie di operazioni asincrone. Se si desidera che vengano eseguiti in un ordine specifico, si promettono in sequenza o si esegue la seconda operazione nella richiamata di completamento della prima operazione asincrona. Se hai N operazioni asincrone indipendenti che dovrebbero essere fatte prima di fare qualcos'altro, allora usa promises e 'Promise.all()'. Non è diverso per avviare un server rispetto a qualsiasi altro coordinamento di più operazioni asincrone. – jfriend00

risposta

0

Ho creato un gist here con un esempio del codice che uso normalmente per questa attività. (Utilizza la libreria di Q promise, ma potrebbe essere facilmente modificata per utilizzare qualsiasi altra lib di promesse).

L'idea di base è descrivere la dorsale dell'app come una sequenza di fasi di inizializzazione asincrona. Ogni passaggio chiama una o più funzioni asincrone e lega il risultato a un nome; il processo di avvio procede solo al successivo passo di inizializzazione dopo che tutti i valori sono stati risolti per il passaggio corrente e i passaggi successivi possono quindi accedere a tutti i valori risolti dai passaggi precedenti. Ciò consente di descrivere facilmente l'ordine di dipendenza dei servizi e dei componenti all'interno dell'app.

Ad esempio, una dorsale può essere definito come segue:

var app = [ 
    { s1: startService1 }, 
    { s2: startService2, s3: startService3 }, 
    { s4: startService4 } 
] 

(Si noti che in ogni definizione fase, solo i riferimenti a ciascuna funzione sono indicati, la funzione start() - mostrato in essenza - richiamerà ciascun funzione nell'ordine corretto).

Ciascuna startXxx vars è una funzione che prende un singolo argomento, e restituisce una promessa differita, ad esempio:

function startService4(app) { 
    var s1 = app.s1; 
    var s2 = app.s2; 
    var deferred = Q.defer(); 
    // ... start the service, do async stuff ... 
    return deferred; 
} 

argomento app della funzione rappresenta la spina dorsale app configurato e risultati da precedenti passaggi di inizializzazione sono disponibili come proprietà denominate.

Ho usato questo modello in sistemi abbastanza complicati e lo trovo un modo semplice, flessibile ed efficace per definire la struttura di alto livello di un sistema.

Problemi correlati