Wrapping legacy callbacks with async/await

Is there a best practice way to wrap legacy callbacks to use async / await?

Example: I am using a comms library that provides the following calls:

  • initSession(X, Y, callback)
    • succeed / fail, res is ignored
  • doComplexTask(A, B, callback)
    • may return multiple times until ‘res’ takes a particular key value
  • cleanupSession(callback)
    • succeed / fail

I’m currently wrapping this using a class and ‘Promise’

class Wrapper
{
  async initSession(X,Y)
  {
    await new Promise((resolve, reject) => {
      this.wrappedObject.initSession(X, Y, (error, res) => {
        if (error)
        {
          reject(error);
        }
        else
        {
          resolve(res);
        }
      }
    }
  }

  async doComplex(A,B)
  {
    await new Promise((resolve, reject) => {
      var resultList = [];
      this.wrappedObject.doComplex(A, B, (error, res) => {
        if (error)
        {
          reject(error);
        }

        res.on('aresult', (thing) => {
          resultList.push(thing);
        );
        res.on('anotherresult', (otherthing) => {
          resultList.push(otherthing.extract());
        );
        res.on('end', () =>
        {
          resolve(resultList);
        }
      }
    }
  }

  // and so on
}

And then in my server code:

async function doStuff(X)
{
  let myThing = createWrapper();

  await myThing.initSession(1,2);
  var someData = await myThing.doComplex(3,X);
  await myThing.cleanUp;
}

Meteor.methods(
{
  'myThing.run'(X)
  {
    doStuff(X);
  },
});

It’s mostly working, but I’m not sure if that’s just co-incidence.

Specific questions:

  • is the above basically sensible? Assume that at some point I’ll do collection updates rather than just processing.
  • Is Promise the right tool for the job?
  • I don’t currently have any try/catch error handling. Where does that go?
  • Do I need to assign the results of my await calls?
  • Is there a quick wrapper for converting a succeed / fail function to an async function along the lines of Meteor.asyncWait?
  • What don’t I know that I need to know?

(PS: the library being wrapped in this case is ldapjs, but I want to understand the general case)

Thanks