2016-01-07 14 views
8

Betrachten Sie ein Beispiel: Ich habe die folgende App (siehe Code-Schnipsel unten). Ich möchte eine persistente Verbindung zur Datenbank und eine persistente Verbindung zu meinem eigenen Dienst (der einen asynchronen Aufruf zum Starten benötigt) während der gesamten Lebensdauer der App haben. Und es gibt ein paar Einstiegspunkte, d. H. Man kann nicht nur über das HTTP-Protokoll auf meine App zugreifen. Natürlich möchte ich die Dienst-Initialisierungscode-Duplizierung vermeiden, und es könnte mehrere solcher async-initialisierenden Dienste geben.Asynchrone Initialisierung von express.js (oder ähnlichen) Anwendungen

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

Im Codeausschnitt oben, durch die Zeit, http (oder Telnet oder andere) Server gestartet wird, gibt es keine Garantie, dass myService bereits initialisiert wurde.

Also muss ich irgendwie meinen App-Erstellungscode reorganisieren. Vorerst bleibe ich mit der nächsten Lösung:

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

Also, meine Frage ist: Was ist der gemeinsame Weg ist, Dienste zu initialisieren asynchronem Aufruf für den Start erforderlich?

+0

Es ist wirklich nicht anders als, wie Sie jede asynchrone Menge von Operationen serialisieren. Wenn Sie möchten, dass sie in einer bestimmten Reihenfolge ausgeführt werden, verketten Sie Versprechungen, oder Sie führen die zweite Operation im Abschlussrückruf der ersten asynchronen Operation aus. Wenn Sie N unabhängige asynchrone Operationen haben, die alle ausgeführt werden sollten, bevor Sie etwas anderes tun, dann verwenden Sie Versprechungen und 'Promise.all()'. Nicht anders beim Starten eines Servers als bei jeder anderen Koordination mehrerer asynchroner Operationen. – jfriend00

Antwort

0

Ich habe eine gist here mit einem Beispiel des Codes erstellt, den ich normalerweise für diese Aufgabe verwende. (Es verwendet die Q-Versprechen-Bibliothek, könnte aber leicht modifiziert werden, um jede andere Versprechen-Bibliothek zu verwenden).

Die Grundidee besteht darin, das App-Backbone als eine Folge asynchroner Initialisierungsschritte zu beschreiben. Jeder Schritt ruft eine oder mehrere asynchrone Funktionen auf und bindet das Ergebnis an einen Namen. Der Startprozess schreitet nur dann zum nächsten Initialisierungsschritt fort, wenn alle Werte für den aktuellen Schritt aufgelöst sind, und nachfolgende Schritte können dann auf alle Werte zugreifen, die durch vorherige Schritte aufgelöst wurden. Dies ermöglicht die einfache Beschreibung der Abhängigkeitsreihenfolge von Diensten und Komponenten innerhalb der App.

Zum Beispiel kann ein Grundgerüst wie folgt definiert werden:

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

(Beachten Sie, dass in jedem Schritt definitionem nur Verweise auf jede Funktion gegeben sind, die start() Funktion - im GIST gezeigt - wird jeder aufrufen Funktion in der richtigen Reihenfolge).

Jedes der startXxx Vars ist eine Funktion, die ein einzelnes Argument und gibt eine latente Versprechen, zum Beispiel:

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

Die App Argument der Funktion stellt die konfigurierte App-Backbone und ergibt sich aus Vorherige Initialisierungsschritte sind als benannte Eigenschaften verfügbar.

Ich habe dieses Muster in ziemlich komplizierten Systemen verwendet, und finde es eine einfache, flexible und effektive Möglichkeit, die High-Level-Struktur eines Systems zu definieren.