Now that is an interesting case, and I think an ideal case for promises: In the first request for a client, create a promise and attach it AND its resolve function to some storage that will outlast the request. If it already exists, don't.
Call thepromise.then() with the renderPage code.
Call next() if you set up a new promise.
Let renderPage resolve that promise instead of rendering.
var promises = {};
var resolvers = {};
function startup(req, res, next) {
var mainRequest = false;
if (!promises[req.clientID]) {
promises[req.clientID] = new Promise(function (resolve, reject) {
resolvers[req.clientID] = { resolve: resolve, reject: reject };
mainRequest = true;
});
}
promises[req.clientID].then(function (data) {
// This is where your rendering ACTUALLY goes.
cleanup();
}).catch(function (err) {
cleanup();
res.render('errors');
// Note that you CAN'T call next(err) here since next has already been called in some branches. c'est la vie. You can work around it but it's ugly.
});
if (mainRequest) next();
function cleanup() {
delete promises[req.clientID];
delete resolvers[req.clientID];
}
}
And renderPage:
functiion renderPage(req, res, next) {
resolvers[req.clientID].resolve(the data used to render);
}
And error handling:
function errorHandler(req, res, next, err) {
resolvers[req.clientID].reject(err);
}
(that could be in your final apiCall5, but I'd probably factor it separately.)
What you've now done is joined these requests. They'll all complete when the promise is resolved.
Aria