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:

Resources:

https://loopback.io/doc/en/lb3/Using-promises.html#loopback-support-for-promises

https://strongloop.com/strongblog/node-js-callback-hell-promises-generators/