1. Promises are a value. They can be passed to other functions. This simplifies a lot of control flow.
2. The `.then` method on a promise is similar to `flatMap` in other languages / libs. The next chain will wait for any nested promises to complete. This flattens callbacks so you can see the flow instead of the pyramid of doom.
3. Native promises include a bit of sugar, such as Promise.all. You need a library to do this with callbacks.
4. Promises are the backbone of async/await. You need them to use it.
Example:
await const [a, b] = Promise.all([getA(), getB()]); const [a, b] = await Promise.all([getA(), getB()]);Controller calls the service.
Service returns a call to a repo with any mapping that needs to occur.
Repo calls out to database or external api and returns the promise.
Makes the work very boring and repetitive for the most part which is a good thing I think.
function someController(req, res) {
UserService.getUser(req.session.user)
.then(SomeService.getSomething)
.then((val) => res.json(val))
.catch(handleError);
}
function getSomething(user) {
return SomeRepo.getSomething(user)
.then(MapSomething)
.catch(alternativeHigherLevelCatch);
}
function getSomething(user) {
return new Promise((resolve, reject) => {
database.getSomething(
'defined parameters',
user,
resolve,
reject
)
});
}You certainly want to call UserService.getUser for many different controllers. Why manually do that for each controller? Simply make a middleware to get the user.
If you take this to its logical conclusion, you end up with small, composable middleware functions, and controllers that are pure functions.
Also agree middleware is a good solution which can go through and provide a user object directly onto the request or another level of abstraction created if you prefer. That was simply to show how multiple service calls could be easily tied together rather than a full and usable example.
A benefit of callbacks though, at least from my experience, is error messages when testing with mocha / chai. I only have experience with jasmine, mocha, and chai but the errors when test driving were much easier to follow with callbacks.
The second one is that you can await a promise, which turns your 1-level-deep code to 0 levels deep.
doSomething.then(stepTwo).then(stepThree).catch(errHandler);
async getDoc(doc) {
const result = await db.get(doc)
console.log('result:', result)
}// instead of:
function getDoc(doc) {
db.get(doc, result => {
console.log('result:', result)
});
}// or
function getDoc(doc) {
db.get(doc)
.then(result => 'result: ' + result)
.then(::console.log)
.catch(::console.error)
}