Reputation: 18435
I currently have a few js files in nodejs which are loaded as module and augment the app object (using express).
So their signatures look like:
module.exports = function(app, callback) {
// ...
callback();
}
So currently as I have about 5 of them my code would look like:
require("./setup/a")(app, function() {
require("./setup/b")(app, function(){
require("./setup/c")(app, function(){
require("./setup/d")(app, function(){
require("./setup/e")(app, function(){
startApp();
})
})
})
})
});
Now that looks unsightly as its the "pyramid of doom", however I am not entirely sure how I need to change this pattern to use Q, as I was assuming I would use Q.fcall(...a).then(...b).etc.done()
. However I am unsure how I pass the app into it and if I need to return the callback for it to process as a promise.
Ideally I do not want to start whacking Q all through my code I only want it in the places where I want to remove the pyramid use cases, so in the above example how do I use Q with promises to pass the app into each required module and then start the app at the end?
Upvotes: 1
Views: 171
Reputation: 5686
Promises are not the silver bullet to callback pyramid of doom. I have seen code where even with promises it looked like a pyramid of doom.
You could get rid of the pyramid and stay with the callback style by doing something like this :
// var app;
// ...etc
var paths = ['a','b','c','d'];
setupNext();
function setupNext() {
var p = paths.pop(); // or shift
var next = paths.length > 0 ? setupNext : startApp
require(p)(app, next);
}
function startApp() {}
Upvotes: 0
Reputation: 276276
Assuming your modules don't already use promises you can do something like this:
module.exports = function(app) {
// do some stuff with app
return new Promise(function(resolve,reject){
// when ready to resolve after some actions on app
resolve(); // you can also return a value here as a cb param
});
};
Promise.all(["./setup/a","./setup/b","./setup/c"].map(require.bind(null,app)))
.then(startApp);
You should however use promises at the lowest level possible, which would mean that you can simply return the promise which you used in the process:
module.exports = function(app){
return something(app).then(function(){
return somethingElseAsyncWithApp(app);
});
};
So the promise constructor isn't required. Note that this answer uses native promises but will also work on libraries that use that syntax like Bluebird. For Q change new Promise
to new Q.Promise
and Promise.all
to Q.all
.
Alternatively, you can change every require(x)
to Q.fcall(require,x)
and use Q.all
on that directly, but that is both slow (Although Q is slow anyway) and more error prone than promisifying the modules directly. It is best to promisify the lowest level API possible.
Upvotes: 2