Node.js Tutorial: Promisify your Node.js Callback Functions
Below is a quick tutorial on how to use promisify() to convert a callback-based function to a Promise-based one. Promises offer more flexibility to developers than callbacks and help you write cleaner, easy-to-read code.
- Identify a Node.js callback function that should be converted to a promise. In this tutorial, we will convert a simple function that takes an image path as its only parameter and returns the images width and height in a JavaScript object.
const sizeOf = require('image-size'); sizeOf(path.join(form.uploadDir, file.name), function (err, dimensions) { console.log(dimensions.width, dimensions.height); if (err) { console.log(`[Error]: ${err}`); } });
- Add the Node.js Util module to the top of your JS file.
const util = require('util'); var sizeOf = require('image-size'); sizeOf(path.join(form.uploadDir, file.name), function (err, dimensions) { console.log(dimensions.width, dimensions.height); if (err) { console.log(`[Error]: ${err}`); } });
- Wrap the original callback function (in this case, the image-size require statement returns a single function) with the promisify utility, which converts it to a function that returns a promise. Delete the old require statement.
const util = require('util'); const sizeOfAsync = util.promisify(require('image-size')); var sizeOf = require('image-size'); sizeOf(path.join(form.uploadDir, file.name), function (err, dimensions) { console.log(dimensions.width, dimensions.height); if (err) { console.log(`[Error]: ${err}`); } });
- Replace your callback function call with the new promisified function and delete the ES5 function expression or ES6 arrow syntax.
const util = require('util'); const sizeOfAsync = util.promisify(require('image-size')); sizeOfAsync(path.join(form.uploadDir, file.name)) sizeOf(path.join(form.uploadDir, file.name), function (err, dimensions) { console.log(dimensions.width, dimensions.height); if (err) { console.log(`[Error]: ${err}`); } });
- Add the Promise's
then
statement and move the callback's return argument and its code from the callback body to thethen
body.const util = require('util'); const sizeOfAsync = util.promisify(require('image-size')); sizeOfAsync(path.join(form.uploadDir, file.name)) .then(dimensions => { console.log("Image dimensions:", dimensions.width, dimensions.height) }) (err, dimensions) { console.log("Image dimensions:", dimensions.width, dimensions.height); if (err) { console.log(`[Error]: ${err}`); } });
- Lastly, add the Promise's
catch
statement and move the callback's error argument and its code from the callback body to thecatch
body.const util = require('util'); const sizeOfAsync = util.promisify(require('image-size')); sizeOfAsync(path.join(form.uploadDir, file.name)) .then(dimensions => { console.log("Image dimensions:", dimensions.width, dimensions.height) }) .catch(err => console.error(`[Error]: ${err}`)); if (err) { console.log(`[Error]: ${err}`); }
- After the conversion, the resulting Promise code should look like the following:
const util = require('util'); const sizeOfAsync = util.promisify(require('image-size')); sizeOfAsync(path.join(form.uploadDir, file.name)) .then(dimensions => { console.log("Image dimensions:", dimensions.width, dimensions.height) }) .catch(err => console.error(`[Error]: ${err}`));
With these changes, we have converted a callback function to a promise and demonstrate how to use the new promise. Now go ahead and replace all your Node.js callback functions with promises to have cleaner and easier to read code.