How to "await" for a callback to return? How to "await" for a callback to return? javascript javascript

How to "await" for a callback to return?


async/await is not magic. An async function is a function that can unwrap Promises for you, so you'll need api.on() to return a Promise for that to work. Something like this:

function apiOn(event) {  return new Promise(resolve => {    api.on(event, response => resolve(response));  });}

Then

async function test() {  return await apiOn( 'someEvent' ); // await is actually optional here                                      // you'd return a Promise either way.}

But that's a lie too, because async functions also return Promises themselves, so you aren't going to actually get the value out of test(), but rather, a Promise for a value, which you can use like so:

async function whatever() {  // snip  const response = await test();  // use response here  // snip}


It's annoying that there isn't a straightforward solution, and wrapping return new Promise(...) is fugly, but I have found an ok work-around using util.promisify (actually it also kinda does the same wrapping, just looks nicer).

function voidFunction(someArgs, callback) {  api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => {    callback(null, response_we_need);  });}

The above function does not return anything, yet. We can make it return a Promise of the response passed in callback by doing:

const util = require('util');const asyncFunction = util.promisify(voidFunction);

Now we can actually await the callback.

async function test() {  return await asyncFunction(args);}

Some rules when using util.promisify

  • The callback must be the last argument of the function that is gonna be promisify
  • The supposed-callback must be in the form (err, res) => {...}

Funny thing is we do not need to ever specifically write what's the callback actually is.


async/await is magic. You can create a function asPromise to handle this kind of situations:

function asPromise(context, callbackFunction, ...args) {    return new Promise((resolve, reject) => {        args.push((err, data) => {            if (err) {                reject(err);            } else {                resolve(data);            }        });        if (context) {            callbackFunction.call(context, ...args);        } else {            callbackFunction(...args);        }    });}

and then use it when you want:

async test() {    return await this.asPromise(this, api.on, 'someEvent');}

the number of args is variable.