valid try promises only node for done catch await async javascript asynchronous callback async-await ecmascript-2017

javascript - try - ¿Cómo "esperar" a que vuelva una devolución de llamada?



javascript wait for async response (4)

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, suponiendo que se garantice que ''someEvent'' se llame una vez y solo una vez, me gustaría que la prueba de función sea una función asíncrona que no regresa hasta que se ejecuta la devolución de llamada, como:

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


Es molesto que no haya una solución sencilla, y el ajuste de return new Promise(...) es fugoso, pero he encontrado una util.promisify usando util.promisify (en realidad también hace el mismo ajuste, solo 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 una Promise de la response pasada en la callback de callback haciendo:

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

Ahora podemos await la callback .

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

Algunas reglas al usar util.promisify

  • La callback debe ser el último argumento de la función que será promisify
  • La supuesta devolución de llamada debe estar en la forma (err, res) => {...}

Lo curioso es que no necesitamos escribir específicamente cuál es realmente la callback .


Puede lograr esto sin devoluciones de llamada, utilice la promesa de espera asíncrona en lugar de devoluciones de llamada aquí, cómo haría esto. 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)''/>


asíncrono / esperar es mágico. Puede crear una función como asPromise para 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 args es variable.


async/await no es mágico. Una función asíncrona es una función que puede desenvolver Promesas para usted, por lo que necesitará api.on() para devolver una Promesa para que eso 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 no obtendrá el valor de test() , sino una Promesa para un valor, que puede usar de la siguiente manera:

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