Cuando se utiliza una devolución de llamada simple como en el siguiente ejemplo:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
¿Cómo se puede cambiar la función para usar async / await? Específicamente, asumiendo que se garantiza que 'someEvent' se llamará una vez y solo una vez, me gustaría que la prueba de función sea una función asíncrona que no regrese hasta que se ejecute la devolución de llamada, como por ejemplo:
async test() {
return await api.on( 'someEvent' );
}

Respuestas:
async/awaitno es magia. Una función asincrónica es una función que puede desenvolver promesas por usted, por lo queapi.on()deberá devolver una promesa para que funcione. Algo como esto:function apiOn(event) { return new Promise(resolve => { api.on(event, response => resolve(response)); }); }Entonces
async function test() { return await apiOn( 'someEvent' ); // await is actually optional here // you'd return a Promise either way. }Pero eso también es una mentira, porque las funciones asíncronas también devuelven Promesas en sí mismas, por lo que en realidad no obtendrá el valor
test(), sino una Promesa por un valor, que puede usar así:async function whatever() { // snip const response = await test(); // use response here // snip }fuente
const apiOn = (event) => new Promise(resolve => api.on(event, resolve));Es molesto que no haya una solución sencilla, y la envoltura
return new Promise(...)es fea, pero he encontrado una solución alternativa aceptableutil.promisify(en realidad, también hace la misma envoltura, solo que se ve mejor).function voidFunction(someArgs, callback) { api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => { callback(null, response_we_need); }); }La función anterior no devuelve nada todavía. Podemos hacer que devuelva uno
Promisede losresponsepasadoscallbackhaciendo:const util = require('util'); const asyncFunction = util.promisify(voidFunction);Ahora podemos realmente
awaitelcallback.async function test() { return await asyncFunction(args); }Algunas reglas al usar
util.promisifycallbackdebe ser el último argumento de la función que va a serpromisify(err, res) => {...}Lo curioso es que no necesitamos escribir nunca específicamente lo que
callbackrealmente es.fuente
async / await es mágico. Puedes crear una función
asPromisepara manejar este tipo de situaciones: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); } }); }y luego úsalo cuando quieras:
async test() { return await this.asPromise(this, api.on, 'someEvent'); }el número de argumentos es variable.
fuente
Puede lograr esto sin devoluciones de llamada, use promise async await en lugar de devoluciones de llamada aquí cómo lo haría. Y también aquí he ilustrado dos métodos para manejar errores.
clickMe = async (value) => { // begin to wait till the message gets here; let {message, error} = await getMessage(value); // if error is not null if(error) return console.log('error occured ' + error); return console.log('message ' + message); } getMessage = (value) => { //returning a promise return new Promise((resolve, reject) => { setTimeout(() => { // if passed value is 1 then it is a success if(value == 1){ resolve({message: "**success**", error: null}); }else if (value == 2){ resolve({message: null, error: "**error**"}); } }, 1000); }); } clickWithTryCatch = async (value) => { try{ //since promise reject in getMessage2 let message = await getMessage2(value); console.log('message is ' + message); }catch(e){ //catching rejects from the promise console.log('error captured ' + e); } } getMessage2 = (value) => { return new Promise((resolve, reject) => { setTimeout(() => { if(value == 1) resolve('**success**'); else if(value == 2) reject('**error**'); }, 1000); }); }<input type='button' value='click to trigger for a value' onclick='clickMe(1)' /> <br/> <input type='button' value='click to trigger an error' onclick='clickMe(2)' /> <br/> <input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(1)'/> <br/> <input type='button' value='handling errors with try catch' onclick='clickWithTryCatch(2)'/>fuente