In Node.js, the util.promisify() function is a powerful tool that allows you to convert callback-based functions into promise-based functions. This conversion enables you to use promise chaining and async/await with APIs that originally relied on callbacks.
Let’s dive into how it works:
Callback-Based Functions:
- Consider an example using the
fs.readFile()function, which reads a file and invokes a callback when done:
const fs = require('fs');
fs.readFile('./package.json', (err, buf) => {
if (err) {
console.error('Error reading file:', err);
return;
}
const obj = JSON.parse(buf.toString('utf8'));
console.log('Project name:', obj.name); // 'masteringjs.io'
});
- The traditional callback approach can lead to callback hell when dealing with multiple asynchronous operations.
Using util.promisify():
util.promisify()transforms thefs.readFile()function into a promise-based function:
const util = require('util');
const readFile = util.promisify(fs.readFile);
// Now you can use `readFile()` with `await`!
try {
const buf = await readFile('./package.json');
const obj = JSON.parse(buf.toString('utf8'));
console.log('Project name:', obj.name); // 'masteringjs.io'
} catch (err) {
console.error('Error reading file:', err);
}
- The
readFile()function now returns a promise, allowing you to handle asynchronous file reading more elegantly.
How Does util.promisify() Work?:
- Under the hood,
util.promisify()adds an extra callback parameter to the original function. - This callback resolves or rejects the promise returned by the promisified function.
- Here’s a simplified custom implementation of
util.promisify()
function promisify(fn) {
return function (...args) {
return new Promise((resolve, reject) => {
fn.apply(this, [...args, (err, res) => {
if (err) {
reject(err);
} else {
resolve(res);
}
}]);
});
};
}
const readFile = promisify(fs.readFile);
// Now you can use `readFile()` with `await`!
Important Considerations:
- Ensure that the original function supports the additional callback argument.
- Be aware of losing context (i.e., incorrect
thisvalue) when using promisified functions.
Remember, util.promisify() simplifies asynchronous code, making it more readable and manageable.