I might be overthinking this, but bear with me... If I have the following code
app.get('/api/endpoint', function(req, res, next) {
new Promise(function() {
// doing something that takes lots of code
return someJson
})
.then(function(someJson) {
// analyze someJson with lots of code
})
.then(function() {
// do more
})
// chain a bunch more promises here
.then(function() {
res.status(200).send(message)
})
.catch(function(err) {
// error handling
})
.finally(function() {
// clean up
})
})
If the promise chain gets very long, it can be a pain to navigate the endpoint. So, I want each step of the promise to be it's own function (to simplify the above code). So I can rewrite the top 2 promises as so:
function findSomeJson() {
return new Promise(function() {
// doing something that takes lots of code
return someJson
})
}
function analyzeSomeJson(someJson) {
return new Promise(function(someJson) {
// analyze someJson with lots of code
})
}
Now, each of these functions can be used in the original example like so:
findSomeJson()
.then(function(someJson) {
return analyzeSomeJson(someJson)
})
// etc...
But, what happens if I need to tweak res
within those promises? Do I need to return res
every time and store someJson within res? And, what happens if I have to use next()? How do I ensure res
is modified at the end of my promise chain? I can't do that in finally()
, do I have to do it in my last promise?
If you really want to be able to mutate res
from within your functions you have to pass it around. I think the easiest/cleanest way to pass it around is to use bind like this:
findSomeJson()
.then(analyzeSomeJson.bind(this, res))
.then(doMore.bind(this, res))
.then(andEvenMore.bind(this, res))...
Then the analyzeSomeJson
definition would look like this:
// .bind makes it so that res is the first argument when it is called
function analyzeSomeJson(res, someJson) {
return new Promise(function(someJson) {
// analyze someJson with lots of code
})
}
But I would probably try to avoid passing around res
so that only your controller has to know about req
and res
. You could move all your functions to a service or services and have the controller determine what needs to happen to res
based on what the service(s) return. Hopefully that will lead to maintainable/testable code.
UPDATE very simple service example
// endpoint.js
var jsonService = require('./jsonService.js');
app.get('/api/endpoint', function(req, res, next) {
jsonService.getJson()
// chain a bunch more promises here
.then(function(json) {
if(json === null) {
return res.status(404).send('Not Found');
}
res.status(200).send(json);
})
.catch(function(err) {
// error handling
});
});
There are many ways you could implement your service but really its just another .js file that you require in to your "controller" or endpoint.js. Whatever you export will be your "public" methods.
// jsonService.js
// "public" methods
var service = {
getJson: function() {
return findSomeJson().then(analyzeSomeJson);
}
};
module.exports = service;
// "private" methods
function findSomeJson() {
return new Promise(function() {
// doing something that takes lots of code
return someJson
});
}
function analyzeSomeJson(someJson) {
return new Promise(function(someJson) {
// analyze someJson with lots of code
});
}