Ao usar um retorno de chamada simples, como no exemplo abaixo:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
Como a função pode ser alterada para usar async / await? Especificamente, supondo que 'someEvent' seja chamado uma vez e apenas uma vez, gostaria que o teste de função fosse uma função assíncrona que não retorna até que o retorno de chamada seja executado, como:
async test() {
return await api.on( 'someEvent' );
}
Respostas:
async/await
não é mágica. Uma função assíncrona é uma função que pode desembrulhar Promises para você, então você precisaráapi.on()
retornar uma Promise para que funcione. Algo assim:function apiOn(event) { return new Promise(resolve => { api.on(event, response => resolve(response)); }); }
Então
async function test() { return await apiOn( 'someEvent' ); // await is actually optional here // you'd return a Promise either way. }
Mas isso também é uma mentira, porque as funções assíncronas também retornam promessas, então você não vai realmente obter o valor de
test()
, mas sim uma promessa de um valor, que você pode usar assim:async function whatever() { // snip const response = await test(); // use response here // snip }
fonte
const apiOn = (event) => new Promise(resolve => api.on(event, resolve));
É irritante que não haja uma solução direta, e embrulhar
return new Promise(...)
é feio, mas eu encontrei uma solução ok para usarutil.promisify
(na verdade ele meio que faz o mesmo embrulho, só parece melhor).function voidFunction(someArgs, callback) { api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => { callback(null, response_we_need); }); }
A função acima não retorna nada, ainda. Podemos fazer com que ele retorne um
Promise
doresponse
passadocallback
, fazendo:const util = require('util'); const asyncFunction = util.promisify(voidFunction);
Agora podemos realmente
await
ocallback
.async function test() { return await asyncFunction(args); }
Algumas regras ao usar
util.promisify
callback
deve ser o último argumento da função que vai serpromisify
(err, res) => {...}
O engraçado é que não precisamos nunca escrever especificamente o que
callback
realmente é.fonte
async / await é mágico. Você pode criar uma função
asPromise
para lidar com este tipo de situação: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); } }); }
e use-o quando quiser:
async test() { return await this.asPromise(this, api.on, 'someEvent'); }
o número de args é variável.
fonte
Você pode conseguir isso sem retornos de chamada, use a promessa async await em vez de retornos de chamada aqui, como eu faria isso. E também aqui ilustrei dois métodos para lidar com erros
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)'/>
fonte