Skip to content

What is the best way to promisify library in js?

In one of my previous posts I realised I needed to promisify (turn a callback into a new promise) a npm module to make clean error handling. Problem is, the more I started to think about the organisation of promisifing a library the more it dawned on me that it could easily become a big fat mess. How should I access the promisified function, in what object? Could I maybe replace the original library functions with the new promisified functions? Should I just create a new object for the promisified functions? Example:

const mongodb = require("mongodb");

const { MongoClient } = mongodb;

//Promisifing MongoClient.connect(), and storing it into connectPr into the original library
mongodb.MongoClient.connectPr = function (url) {
  const options = { useNewUrlParser: true, useUnifiedTopology: true };

  const promise = new Promise(function (resolve, reject) {
    MongoClient.connect(url, options, (error, client) => {
      if (error) reject(error);
      else resolve(client);
    });
  });

  return promise;
};

//Exporting whole module with added functions
module.exports = mongodb;

What I am doing here is just modifing the original library and adding the new function connectPr into it. Then I export it and use it like this in another file:

const mongodb = require("./helperMongoDB");
const { MongoClient } = mongodb;

const connectionURL = "mongodb://127.0.0.1:27017";
const databaseName = "tasker";

//Using new connectPr function
(async function () {
  const client = await MongoClient.connectPr(connectionURL);
  const db = client.db(databaseName);

  db.collection("tasks").insertOne(
      {
        description: "Clean the house",
        completed: true,
      },
    (error, result) => {
      if (error) {
        console.error(error);
        return;
      }
  
      console.log(result.ops);
    }
  );
})();

As u can see I can still use all the original properties from the module and I can also use my connectPr function. This works but its nothing pretty. I am sure that if I worked in a team of people that most of them would be pretty confused on why I am not requiring the library normally and why it is hidden somwhere in a helper file. What is the standard on doing this kind of thing? Is promisifing a callback function even a practise?

Answer

Be sure to first check that the asynchronous API does not already provide a promise interface. In your question you give the example of mongodb. This node API’s asynchronous methods will return a promise when the callback argument is not provided.

For instance, take the connect method. The documentation says:

Returns:

Promise if no callback passed

So in an async function body you can write:

const client = await MongoClient.connect(url, options);

In case of the Mongoose library (built on top of the Node MongoDb driver API), when using query methods, you may need to chain an .exec() call, as is discussed in the answers to What does the exec function do?.

Any asynchronous library that wants to remain on track, will have a promise API included. If really this is not the case, look at Node’s util.promisify