При использовании простого обратного вызова, такого как в примере ниже:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
Как можно изменить функцию для использования async / await? В частности, предполагая, что 'someEvent' гарантированно будет вызываться один раз и только один раз, я бы хотел, чтобы функциональный тест был асинхронной функцией, которая не возвращается, пока не будет выполнен обратный вызов, например:
async test() {
return await api.on( 'someEvent' );
}
Ответы:
async/await
это не волшебство. Асинхронная функция - это функция, которая может разворачивать Promises за вас, поэтому вам нужноapi.on()
будет вернуть Promise, чтобы это сработало. Что-то вроде этого:function apiOn(event) { return new Promise(resolve => { api.on(event, response => resolve(response)); }); }
затем
async function test() { return await apiOn( 'someEvent' ); // await is actually optional here // you'd return a Promise either way. }
Но это тоже ложь, потому что асинхронные функции также возвращают сами обещания, поэтому вы на самом деле не собираетесь получать значение из
test()
, а, скорее, обещание для значения, которое вы можете использовать следующим образом:async function whatever() { // snip const response = await test(); // use response here // snip }
источник
const apiOn = (event) => new Promise(resolve => api.on(event, resolve));
Раздражает то, что нет простого решения, и упаковка
return new Promise(...)
неуправляема, но я нашел подходящее решениеutil.promisify
(на самом деле она также как бы делает ту же упаковку, только выглядит лучше).function voidFunction(someArgs, callback) { api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => { callback(null, response_we_need); }); }
Вышеупомянутая функция пока ничего не возвращает. Мы можем сделать это возвращать
Promise
изresponse
проходил вcallback
выполнив:const util = require('util'); const asyncFunction = util.promisify(voidFunction);
Теперь мы можем на самом деле .
await
callback
async function test() { return await asyncFunction(args); }
Некоторые правила при использовании
util.promisify
callback
Должен быть последним аргументом функции , которая собирается бытьpromisify
(err, res) => {...}
Забавно то, что нам не нужно когда-либо специально писать, что есть на
callback
самом деле.источник
async / await - это волшебство. Вы можете создать функцию
asPromise
для обработки таких ситуаций: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); } }); }
а затем используйте его, когда хотите:
async test() { return await this.asPromise(this, api.on, 'someEvent'); }
количество аргументов варьируется.
источник
Вы можете добиться этого без обратных вызовов, используйте обещание async await вместо обратных вызовов, как я бы это сделал. А также здесь я проиллюстрировал два метода обработки ошибок.
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)'/>
источник