How to "await" for a callback to return?
When using a simple callback such as in the example below:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
How can the function be changed to use async / await? Specifically, assuming 'someEvent' is guaranteed to be called once and only once, I'd like the function test to be an async function which does not return until the callback is executed such as:
async test() {
return await api.on( 'someEvent' );
}
Solution 1:
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
}
Solution 2:
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.