JavaScript Promisify

JavaScript Promisify

What is Promisification?

Promisification represents transformation. It’s the conversion of a callback-accepting function into a promise-returning function.

What are Callbacks?

A JavaScript callback is a function that is supposed to run after another function’s completion. These are the functions that are passed to another function as arguments that are invoked inside that main function to complete some kind of operation.

Why do we need to convert callbacks to promises?

Callbacks have issues with memory leaks that lead to poor performance because we don’t have control over when it is called, under what context, or how many times it’s being called.

Using promises, we control these factors (especially error handling) so the code is more readable and maintainable.

If you have multiple tasks that need to run sequentially, one after another, and the output of the previous task is required to start the next task. So to implement this, we will apply nested callbacks. To manage errors, We need to specify an error argument in each callback which is redundant. Promise or async-await, you can just add a .catch method or block which will catch any errors that occur in the promise chain.

Callback based Programming

function getSum(a, b, cb) {
    if (!a || !b) {
        cb(new Error('Please provide inputs'));
    }
    return cb(null, a + b); // First parameter refers to Error
}

getSum(10, 10, (err, result) => {
    if (err) {
        console.log(err);
    } else {
        console.log('output with callback based fn ', result);
    }
})

// output with callback based fn  20

Custom Promisify Function

Create an Outer function named Promisify that will take our async function as an argument. This Outer function will return an Inner function.

function promisify(asyncFn) {
    return function (...inputs) {
         console.log(inputs);
    }
}

When calling the Inner function, we have to return a promise-based object, so create a new Promise inside the inner function.

function promisify(asyncFn) {
    return function (...inputs) {
        return new Promise((resolve, reject) => {
            
        })
    }
}

Inside Promise, call the async function (a callback-based function that we have to covert) with input arguments.
In Callback-based programming, the last parameter is always a callback function named cb. We can see this in the getSum function.
If we receive an error reject the promise and if we get the result resolve the promise.

function promisify(asyncFn) {
    return function (...inputs) {
        return new Promise((resolve, reject) => {
            // Call async function and pass callback function as last parameter
            asyncFn(...inputs, (err, result) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(result);
                }
            });
        })
    }
}

Run the above program.

function getSum(a, b, cb) {
    if (!a || !b) {
        cb(new Error('Please provide inputs'));
    }
    return cb(null, a + b); // First parameter refers to Error
}

// we have to convert above callback based function so pass this our custom promisify function.

const p = promisify(getSum);

p(10, 10).then((res) => {
    console.log('output with promisify', res);
}).catch(console.error)

// output with callback based fn  20

// Try with no input parameter
p().then((res) => {
    console.log('output with promisify', res);
}).catch(console.error)

// TypeError: cb is not a function

Handle Error cases

This is a common Promisify function that will convert to every async function. In case we don’t send enough arguments which are required then it will give an error like ‘TypeError: cb is not a function’.
So let’s add an If condition in our previous code to make this error more specific.

// return a promise
function promisify(asyncFn) {
    return function (...inputs) {
        return new Promise((resolve, reject) => {
            // This If is extra safety check for validate number of input arguments which required to async function
            // Reject Promise incase sufficient arguments are not passed
            if (inputs.length !== asyncFn.length - 1) {
                reject('Please validate number of inputs parameters')
            }
            // Call async function and pass callback function as last parameter
            asyncFn(...inputs, (err, result) => {
                if (err) {
                    reject(err);
                } else {
                    resolve(result);
                }
            });
        })
    }
}

Now check all error cases to run the above function.

p(10).then((res) => {
    console.log('output with promisify', res);
}).catch(console.error)
// Please validate number of inputs parameters

p().then((res) => {
    console.log('output with promisify', res);
}).catch(console.error)
//Please validate number of inputs parameters

p(1, 2, 3, 4).then((res) => {
    console.log('output with promisify', res);
}).catch(console.error)
// Please validate number of inputs parameters

Node JS Promisify of Util package – https://nodejs.org/api/util.html#utilpromisifyoriginal

JavaScript Promisify

Leave a Reply

Your email address will not be published.