Loopback Asynchronous code: Callback vs Promises
Understanding promises
The best way to think of Promises is that they bring keywords like return
and try/catch
to asynchronous code.
For example, this is how synchronous code looks like:
function returnSomething() {
try {
doSomething();
doSomethingElse();
return true;
} catch (err) {
console.log(err);
}
}
And asynchronous code:
function returnSomething() {
return doSomething().then(function () {
return doSomethingElse();
}).then(function () {
return true;
}).catch(function (err) {
console.log(err);
});
}
LoopBack supports for Promises and Callback
The Loopback3 provides both Callback format and Promises format.
The Callback format looks like this:
City.findById(id, (err, city) => {
if (err) {
// oh noes! we got an error
} else {
// okay, found data
}
});
And the Promises format looks like this:
City.findById(id)
.then(result => cb(null, result))
.catch(cb);
Basically, if you include a callback as the last argument in a function, then Loopback assumes you want to use Callback style. Otherwise, it assumes you want the Promises style.
Let’s talk about Promises
I usually use the Promise format for some reasons:
- Callbacks easily lead to spaghetti code.
- Promises generally lead to better code organization.
Catching Errors
The big advantage of working with Promises in asynchronous code is that you can always attach a catch function to the end of a big promise chain, and any errors that occur along the way will show up at the end.
For example, with Callback style catching error appears several times:
Model.findOne({}, (err, model) => {
if (err) return cb(err); // must catch error here
Model.create(
{
name: 'other model'
},
(err, rs) => {
if (err) return cb(err); // must catch error here
cb(null, rs);
}
);
});
But with Promise style there is just one place to catch errors:
Model.findOne({}})
.then(model => {
return Model.create({
name: 'other model'
});
})
.then((rs) => cb(null, rs))
.catch(err => cb(err)); // only catch one time for any error
An alternate way of catching errors
If you’ve been doing Promises for awhile, you might have seen this instead:
Model.find().then(res => {
// got datas
}, err => {
// got an error
})
This is equivalent to:
Model.find().then(res => {
// got datas
}).catch(err => {
// got an error
})
Notes
Promise support in LoopBack is still in progress. The following are completed:
- Strong Remoting
- Operation hooks
- DAO and relation methods
- loopback-datasource-juggler methods like
automigrate
,autoupdate
,discover*
, etc. - Some built-in models
Resources:
https://loopback.io/doc/en/lb3/Using-promises.html#loopback-support-for-promises
https://strongloop.com/strongblog/node-js-callback-hell-promises-generators/