Podczas korzystania z prostego wywołania zwrotnego, takiego jak w poniższym przykładzie:
test() {
api.on( 'someEvent', function( response ) {
return response;
});
}
Jak można zmienić funkcję, aby używała async / await? W szczególności zakładając, że „someEvent” jest wywoływane raz i tylko raz, chciałbym, aby test funkcji był funkcją asynchroniczną, która nie powraca do momentu wykonania wywołania zwrotnego, takiego jak:
async test() {
return await api.on( 'someEvent' );
}
Odpowiedzi:
async/await
nie jest magią. Funkcja asynchroniczna to funkcja, która może rozpakowywać obietnice za Ciebie, więcapi.on()
aby to zadziałało, musisz zwrócić obietnicę. Coś takiego:function apiOn(event) { return new Promise(resolve => { api.on(event, response => resolve(response)); }); }
Następnie
async function test() { return await apiOn( 'someEvent' ); // await is actually optional here // you'd return a Promise either way. }
Ale to też jest kłamstwo, ponieważ funkcje asynchroniczne również zwracają same Obietnice, więc tak naprawdę nie uzyskasz wartości z
test()
Obietnicy dla wartości, której możesz użyć w następujący sposób:async function whatever() { // snip const response = await test(); // use response here // snip }
źródło
const apiOn = (event) => new Promise(resolve => api.on(event, resolve));
Irytujące jest to, że nie ma prostego rozwiązania, a owijanie
return new Promise(...)
jest niezbyt dobre, ale znalazłem dobre obejścieutil.promisify
(w rzeczywistości to również robi to samo owijanie, po prostu wygląda ładniej).function voidFunction(someArgs, callback) { api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => { callback(null, response_we_need); }); }
Powyższa funkcja jeszcze nic nie zwraca. Możemy zrobić to zwróci
Promise
zresponse
przekazanycallback
wykonując:const util = require('util'); const asyncFunction = util.promisify(voidFunction);
Teraz możemy rzeczywiście .
await
callback
async function test() { return await asyncFunction(args); }
Niektóre zasady podczas używania
util.promisify
callback
Musi być ostatni argument funkcji, że to będziepromisify
(err, res) => {...}
Zabawne jest to, że nigdy nie musimy szczegółowo opisywać tego, co jest w
callback
rzeczywistości.źródło
async / await to magia. Możesz utworzyć funkcję
asPromise
do obsługi tego rodzaju sytuacji: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); } }); }
a następnie użyj go, kiedy chcesz:
async test() { return await this.asPromise(this, api.on, 'someEvent'); }
liczba argumentów jest zmienna.
źródło
Możesz to osiągnąć bez wywołań zwrotnych, użyj promise async await zamiast callbacków tutaj, jak bym to zrobił. Tutaj również zilustrowałem dwie metody obsługi błędów
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)'/>
źródło