콜백이 반환 될 때까지 "대기"하는 방법은 무엇입니까?


100

아래 예와 같이 간단한 콜백을 사용하는 경우 :

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

async / await를 사용하도록 함수를 어떻게 변경할 수 있습니까? 특히 'someEvent'가 한 번만 호출된다고 가정하면 함수 테스트가 다음과 같이 콜백이 실행될 때까지 반환되지 않는 비동기 함수가되기를 바랍니다.

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

1
참고로 ES7 / ES2016 사양이 마무리되었으며 async / await가 포함되어 있지 않습니다. 현재로서는 3 단계 제안 일뿐 입니다.
Dan Prince

놀랍습니다. 포함되기를 바랍니다. 정보를 주셔서 감사합니다 @DanPrince
sean2078

답변:


146

async/await마법이 아닙니다. 비동기 함수는 약속을 풀 수있는 함수이므로 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.
}

그러나 그것은 거짓말이기도합니다. 왜냐하면 비동기 함수는 Promise 자체를 반환하기 때문입니다. 따라서 실제로 값을에서 얻는 test()것이 아니라 다음과 같이 사용할 수있는 Promise 값을 얻을 것입니다.

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

3
약속을 반환하는 함수의 더 짧은 버전 : const apiOn = (event) => new Promise(resolve => api.on(event, resolve));
Felipe Plets

7

간단한 해결책이없고 래핑 return new Promise(...)이 흐릿하지만 나는 사용하여 괜찮은 해결 방법을 찾았습니다 util.promisify(실제로는 좀 더 멋지게 보입니다).

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

위의 함수는 아직 아무것도 반환하지 않습니다. 다음 을 수행 Promise하여 response전달 된 a 를 반환하도록 할 수 있습니다 callback.

const util = require('util');

const asyncFunction = util.promisify(voidFunction);

이제 우리는 실제로 수 awaitcallback.

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

사용할 때 몇 가지 규칙 util.promisify

  • 은 ( callback는) 될 함수의 마지막 인수 여야합니다.promisify
  • 예상 콜백은 다음 형식이어야합니다. (err, res) => {...}

재밌는 점은 우리가 callback실제로 무엇인지 구체적으로 쓸 필요가 없다는 것입니다.


3

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

인수의 수는 가변적입니다.


1

콜백없이 이것을 달성 할 수 있습니다. 여기서 콜백 대신 promise 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)'/>

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.