I have recently been programming a REST API using the Node.js Express framework. Express starts developers out with callbacks for safe asynchronous functions.
Such as:
// input object
var obj = {
email: 'user@test.com',
firstName: 'jane',
lastName: 'doe',
favorites: {
food: 'pizza',
animal: 'cat'
}
}
// business logic
const helpersCB = {
createFullNameCB: function (firstName, lastName, callback) {
if (firstName && lastName) {
const fullName = firstName.concat(' ', lastName);
callback(null, fullName);
} else {
callback('No firstName and lastName!', null);
}
}
}
// callback function
function cb(err, data) {
if (err) {
console.log(`error: ${err}`);
}
console.log(`FullName: ${data}`);
return data;
}
helpers.createFullNameCB(obj.f, obj.lastName, cb);
Express has been easy to learn and get running quickly, but while writing the API, I encountered situations where I had a callback within callback within callback, a.k.a. callback hell. It is hard to keep track of the scoping of each callback and frustrating to debug errors. After researching this problem, I found other developers with similar issues and the JavaScript Promise API looked like an approach that solved these issues.
Here is the same function as above, but using a promise-based approach.
// promise
const helpersPromise = {
createFullNamePromise: async function (firstName, lastName) {
return new Promise((resolve, reject) => {
if (firstName && lastName) {
const fullName = firstName.concat(' ', lastName);
resolve(fullName);
} else {
reject('No firstname and lastName!')
}
})
}
}
var fullNamePromise = async () => {
await helpersPromise.createFullNameP(obj.firstName, obj.lastName)
.then((result) => {
console.log(`result: ${result}`);
return result;
})
.catch((error) => {
console.log(`error creating fullName: ${error}`);
});
}
Through the resolve
/reject
pattern, it is easy to reason about what is going on in promise-based functions. No longer do I have to refer outside of the function scope to understand what the function is actually returning or what data it is operating on. I can quickly see the business logic in the resolve
/reject
and then
/catch
. Once I started writing promises, I quickly refactored the entire API to use promises. I have seen many benefits including readable, maintainable code for other developers.
I would encourage other Nodejs or Javascript developers to embrace promises and there are great tutorials online, especially the Mozilla learning guide.