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 bepromisify
- 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.