These is gonna be a meme-tastic blog post. Strap yourself in.
So, I guess you read the [super]clickbaity title, and couldn't resist it, huh? Well, no worries, I promise you this is gonna be good.
#History lesson
NodeJS initially shipped with callbacks for its amazing asynchronous model which made it an overnight star in the first place. And callbacks were cool. You could read a huge file, and write the code in such a way to simply wait for the response to come out. This applied to database reads, XHR calls(ajax). This model was groundbreaking when it came out.
Callbacks follow this pattern
callback(param1, param2, param3, (error, data)) {
// Do something
}
Note, there can be any number of parameters before the actual callback as the last parameter, and the callback doesn't have to have only data
either, it can be any number of parameters, or not have any, other than the error
.
But there's a funny thing that happens when you dive super deep into something. YoU fInD oUt ItS fLaWs.
fs.readdir(source, function (err, files) {
if (err) {
console.log('Error finding files: ' + err);
} else {
files.forEach(function (filename, fileIndex) {
console.log(filename);
gm(source + filename).size(function (err, values) {
if (err) {
console.log('Error identifying file size: ' + err);
} else {
console.log(filename + ' : ' + values);
aspect = values.width / values.height;
widths.forEach(
function (width, widthIndex) {
height = Math.round(width / aspect);
console.log('resizing ' + filename + 'to ' + height + 'x' + height);
this.resize(width, height).write(dest + 'w' + width + '_' + filename, function (err) {
if (err) console.log('Error writing file: ' + err);
});
}.bind(this)
);
}
});
});
}
});
Oh boy, my eyes bleed
I guess this twitter meme was on point
#Enter promises
Promises radicalized the whole scene. They made our code even cleaner. They follow a much simpler structure. No need for all that indentation inside indentation inside indentation. Max to max 1 level of indentation is needed
const finalData = fetch('https://api.example/com')
.then((req) => req.json())
.then((data) => cleanUpData(data))
.then((data) => doEpicShit(data));
Using the .then
pattern made life super easy.
And then came async/await. Above code became even simpler:
const req = await fetch('https://api.example.com');
const data = await req.json();
const finalData = cleanUpData(data);
doEpicShit(finalData);
So flat
#Callback to Promise
Converting callbacks to promises in NodeJS is very simple. If you're using fs.readdir
.
We'll redefine it:
const readdirPromise = (folderPath) =>
new Promise((resolve, reject) => {
return fs.readdir(folderPath, (err, filenames) =>
err != null ? reject(err) : resolve(filenames)
);
});
Just do it for every single function
NOTE: The above part was a joke. You don't need to redefine every single callback function like that.
#Serious way...
Since Node 8, there's been a built-in helper function into Node, called promisify
. It's the easiest way to promisify your callbacks. Check it out
const { promisify } = require('util');
const callbackP = promisify(callback);
await callbackP();
That's it. Just pass your callback to promisify
, and it will magically be .then
able and await
able.
#About filesystem API...
Most of the time, you'll end up needing promisification for the fs
API in NodeJS. But there's a good news. fs
already ships with promise based version of its functions.
Check out my article to know this uncanny art: Simple code with fs.promises and async await.
Hope you got something good out of it .
Thank you for reading.