最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Asynchronous initialization of express.js (or similar) apps - Stack Overflow

programmeradmin0浏览0评论

Consider an example: I have the following express.js app (see code snippet below). I want to have one persistent connection to the DB, and one persistent connection to my own service (which required async call to start) during entire app lifetime. And there are a few entry points, i.e. one can access my app not only via HTTP protocol. Of course, I want to avoid service initialization code duplication and there could be several such async-initializing services.

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

In the code snippet above, by the time http (or telnet, or any other) server is starting, there is no guarantee, that myService already has initialized.

So, I have to somehow reorganize my app creation code. For now I stick with the next solution:

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

So, my question is: what is the mon way to initialize services required asynchronous call to start?

Consider an example: I have the following express.js app (see code snippet below). I want to have one persistent connection to the DB, and one persistent connection to my own service (which required async call to start) during entire app lifetime. And there are a few entry points, i.e. one can access my app not only via HTTP protocol. Of course, I want to avoid service initialization code duplication and there could be several such async-initializing services.

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

In the code snippet above, by the time http (or telnet, or any other) server is starting, there is no guarantee, that myService already has initialized.

So, I have to somehow reorganize my app creation code. For now I stick with the next solution:

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

So, my question is: what is the mon way to initialize services required asynchronous call to start?

Share Improve this question edited Jan 7, 2016 at 17:32 Ivan Velichko asked Jan 7, 2016 at 16:34 Ivan VelichkoIvan Velichko 6,7197 gold badges49 silver badges97 bronze badges 1
  • It's really no different than how you serialize any async set of operations. If you want them done in a specific order, you chain promises or you do the 2nd operation in the pletion callback of the first async operation. If you have N independent async operations that should all be done before you do something else, then use promises and Promise.all(). No different for starting a server vs. any other coordination of multiple async operations. – jfriend00 Commented Jan 7, 2016 at 21:29
Add a ment  | 

2 Answers 2

Reset to default 3

I would remend you to promisify the initialization function of your services(s) and then use them in the following manner:

const app = require('express')();
const util = require('util');
const myService = require('./myService');
const myServiceInit = util.promisify(myService.init);
Promise.all([myServiceInit]).then(() => {
  // delayed listening of your app
  app.listen(2000);
}).catch(err => {
 // handle error here
});

I've used Promise.all in order for you to add initialization of multiple internal services.

The pre-requisite of promisifying your init function is that it should be using an error first callback mechanism. You can read more about it here Node Official Doc

Hope this helps your cause.

I've created a gist here with a sample of the code I normally use for this task. (It uses the Q promise library, but could easily be modified to use any other promises lib).

The basic idea is to describe the app backbone as a sequence of asynchronous initialization steps. Each step calls one or more async functions and binds the result to a name; the startup process only progresses to the next initialization step once all values are resolved for the current step, and subsequent steps can then access all values resolved by previous steps. This allows the dependency order of services and ponents within the app to be easily described.

For example, a backbone can be defined as follows:

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

(Note that in each step definition, just references to each function are given; the start() function - shown in the gist - will invoke each function in the correct order).

Each of the startXxx vars is a function which takes a single argument, and returns a deferred promise, e.g.:

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

The function's app argument represents the configured app backbone, and results from previous initialization steps are available as its named properties.

I've used this pattern in fairly plicated systems, and find it a simple, flexible and effective way to define a system's high level structure.

发布评论

评论列表(0)

  1. 暂无评论