webentwicklung-frage-antwort-db.com.de

Wie kann man auf einen Rückruf "warten"?

Bei Verwendung eines einfachen Rückrufs wie im folgenden Beispiel:

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

Wie kann die Funktion geändert werden, um async/await zu verwenden? Unter der Annahme, dass "someEvent" garantiert einmal und nur einmal aufgerufen wird, möchte ich, dass es sich bei der Funktion test um eine async-Funktion handelt, die erst zurückkehrt, wenn der Rückruf ausgeführt wird.

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

async/await ist keine Zauberei. Eine asynchrone Funktion ist eine Funktion, mit der Sie Promises auspacken können. Sie müssen also api.on() verwenden, um ein Promise zurückzusenden. Etwas wie das:

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

Dann

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

Aber das ist auch eine Lüge, weil asynchrone Funktionen auch Promises selbst zurückgeben, so dass Sie nicht wirklich den Wert aus test() bekommen, sondern ein Promise für einen Wert, den Sie wie folgt verwenden können:

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

Es ist ärgerlich, dass es keine unkomplizierte Lösung gibt, und return new Promise(...) zu verpacken ist schwer, aber ich habe mit util.promisify eine Umgehung gefunden.

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

Die obige Funktion gibt noch nichts zurück. Wir können eine Promise der in response übergebenen callback zurückgeben, indem Sie

const util = require('util');

const asyncFunction = util.promisify(voidFunction);

Jetzt können wir await die callback.

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

Einige Regeln bei der Verwendung von util.promisify

  • callback muss das letzte Argument der Funktion sein, die promisify sein wird.
  • Der vermeintliche Rückruf muss in der Form (err, res) => {...} sein.

Das Witzige daran ist, dass wir nie genau schreiben müssen, was die callback eigentlich ist. 

3
ErikD

Sie können dies ohne Rückrufe erreichen, verwenden Sie hier asiseing asise warten anstelle von Rückrufen, wie ich dies tun würde. Und auch hier habe ich zwei Methoden dargestellt, um Fehler zu behandeln 

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

1

async/await ist magisch. Sie können eine Funktion asPromise erstellen, um mit diesen Situationen umzugehen:

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

und benutze es dann, wenn du willst:

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

argumente sind Dynamik.

0
negstek