Geri aramanın geri gelmesi için nasıl "beklenir"?


100

Aşağıdaki örnekte olduğu gibi basit bir geri arama kullanırken:

test() {
  api.on( 'someEvent', function( response ) {
    return response;
  });
}

Async / await işlevini kullanmak için işlev nasıl değiştirilebilir? Spesifik olarak, 'someEvent'in yalnızca bir kez çağrılmasının garanti edildiğini varsayarsak, işlev testinin aşağıdaki gibi geri arama yürütülene kadar geri dönmeyen bir zaman uyumsuz işlev olmasını istiyorum:

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

1
Sadece referans olması için, ES7 / ES2016 spesifikasyonu son haline getirildi ve async / await içermiyor. Şu anda bu sadece bir 3. aşama teklifi .
Dan Prince

Bu şaşırtıcı - Çok umarım dahil edilir! @DanPrince bilgisi için teşekkürler
sean2078

Yanıtlar:


147

async/awaitsihir değil. Zaman uyumsuz bir işlev, Promises'i sizin için çözebilen bir işlevdir, bu nedenle api.on()bunun çalışması için bir Promise vermeniz gerekir . Bunun gibi bir şey:

function apiOn(event) {
  return new Promise(resolve => {
    api.on(event, response => resolve(response));
  });
}

Sonra

async function test() {
  return await apiOn( 'someEvent' ); // await is actually optional here
                                      // you'd return a Promise either way.
}

Ama bu da bir yalan, çünkü eşzamansız işlevler de Promises'i kendileri döndürüyor, bu yüzden aslında değeri test()bir değer için bir Promise'den almayacaksınız , bunun yerine şu şekilde kullanabilirsiniz:

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

3
Bir söz veren işlev için daha kısa bir sürüm: const apiOn = (event) => new Promise(resolve => api.on(event, resolve));
Felipe Plets

7

Basit bir çözüm olmaması can sıkıcı ve paketlemenin return new Promise(...)aceleci, ancak kullanımda iyi bir çözüm buldum util.promisify(aslında aynı sargıyı da yapıyor, sadece daha güzel görünüyor).

function voidFunction(someArgs, callback) {
  api.onActionwhichTakesTime(someMoreArgs, (response_we_need) => {
    callback(null, response_we_need);
  });
}

Yukarıdaki işlev henüz hiçbir şey döndürmüyor. Aşağıdakileri yaparak geçilenlerin bir Promisekısmını döndürmesini sağlayabiliriz :responsecallback

const util = require('util');

const asyncFunction = util.promisify(voidFunction);

Şimdi biz aslında can .awaitcallback

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

Kullanırken bazı kurallar util.promisify

  • callbackOlacak olan fonksiyonun son argüman olmalıdırpromisify
  • Sözde geri arama biçiminde olmalıdır (err, res) => {...}

İşin garibi, callbackgerçekte ne olduğunu asla özel olarak yazmamıza gerek yok .


3

async / await sihirdir. asPromiseBu tür durumların üstesinden gelmek için bir işlev oluşturabilirsiniz :

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);
        }
    });
}

ve sonra istediğiniz zaman kullanın:

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

bağımsız değişken sayısı değişkendir.


1

Bunu geri aramalar olmadan başarabilirsiniz, burada geri arama yerine promise async await'i kullanın, bunu nasıl yapardım. Ve ayrıca burada hataları ele almak için iki yöntem gösterdim

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)'/>

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.