asynchronous初始化express.js(或类似的)应用程序

考虑一个例子:我有以下express.js应用程序(请参阅下面的代码片段)。 我想有一个持久连接到数据库,并且一个持久连接到我自己的服务(这需要asynchronous调用来启动)在整个应用程序生命周期。 还有几个入口点,即不仅可以通过HTTP协议访问我的应用程序。 当然,我想避免服务初始化代码重复,并可能有几个如同步初始化服务。

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

在上面的代码片段中,当http(或者telnet或者其他的)服务器启动的时候,我们不能保证myService已经被初始化了。

所以,我必须以某种方式重新组织我的应用程序创build代码。 现在我坚持下一个解决scheme:

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

所以,我的问题是:初始化服务所需的asynchronous调用启动的常用方法是什么?

我用这个任务通常使用的代码示例创build了一个要点 。 (它使用Q诺言库,但可以很容易地修改使用任何其他诺言库)。

基本思想是将应用程序主干描述为一系列asynchronous初始化步骤。 每个步骤调用一个或多个asynchronous函数并将结果绑定到一个名称; 一旦当前步骤的所有值都被parsing,启动过程只进行到下一个初始化步骤,随后的步骤可以访问通过前面的步骤解决的所有值。 这使得应用程序中服务和组件的依赖性顺序很容易被描述。

例如,主干可以定义如下:

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

(请注意,在每个步骤定义中,只给出了每个函数的引用;要点中显示的start()函数将以正确的顺序调用每个函数)。

每个startXxxvariables都是一个函数,它接受一个参数,并返回一个延迟的承诺,例如:

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

该函数的应用程序参数表示configuration的应用程序主干,以前的初始化步骤的结果可用作其命名的属性。

我在相当复杂的系统中使用了这种模式,发现它是定义系统高层结构的简单,灵活和有效的方法。