[javascript] 비동기 / 대기 구문에서 거부하는 방법?

async / await 함수가 반환 한 약속을 어떻게 거부 할 수 있습니까?

예를 들어 원래

foo(id: string): Promise<A> {
  return new Promise((resolve, reject) => {
    someAsyncPromise().then((value)=>resolve(200)).catch((err)=>reject(400))
  });
}

async / await로 번역

async foo(id: string): Promise<A> {
  try{
    await someAsyncPromise();
    return 200;
  } catch(error) {//here goes if someAsyncPromise() rejected}
    return 400; //this will result in a resolved promise.
  });
}

이 경우 어떻게이 약속을 올바르게 거절 할 수 있습니까?



답변

가장 좋은 방법이다 포장 값와 거부 약속의 결과 포장 값 :throwErrorError

} catch (error) {
    throw new Error(400);
}

throw값만 가질 수 있지만 스택 추적 정보는 없습니다.

} catch (error) {
    throw 400;
}

또는 Error값을 줄 바꿈하여 거부 된 약속을 반환 하지만 관용적이지는 않습니다.

} catch (error) {
    return Promise.reject(new Error(400));
}

또는 단지 return Promise.reject(400);컨텍스트 정보가 없습니다.

(귀하 의 경우을 사용 TypeScript하고 foo의 retrn value가 Promise<A>이면을 사용합니다 return Promise.reject<A>(400 /*or error*/);)

에서 async/의 await상황, 마지막은 아마 의미가 일치하지 약간이지만, 그것은 작업을 수행합니다.

를 던지면 구문으로 결과를 Error소비하는 모든 것과 잘 어울 립니다.fooawait

try {
    await foo();
} catch (error) {
    // Here, `error` would be an `Error` (with stack trace, etc.).
    // Whereas if you used `throw 400`, it would just be `400`.
}


답변

또한 catch()후드 아래에서 여전히 약속이 반환되기 때문에 비동기 작업을 호출 한 후에 단순히 함수 를 연결할 수 있다고 언급해야합니다 .

await foo().catch(error => console.log(error));

이런 식으로 try/catch구문이 마음에 들지 않으면 구문을 피할 수 있습니다 .


답변

약속을 받아들이고 오류가 없으면 데이터가 포함 된 배열을 반환하고 오류가 있으면 오류를 반환하는 래퍼 함수 를 만들 수 있습니다 .

function safePromise(promise) {
  return promise.then(data => [ data ]).catch(error => [ null, error ]);
}

ES7비동기 함수에서 다음 과 같이 사용하십시오 .

async function checkItem() {
  const [ item, error ] = await safePromise(getItem(id));
  if (error) { return null; } // handle error and return
  return item; // no error so safe to use item
}


답변

비동기 함수를 작성하는 더 좋은 방법은 시작에서 보류중인 약속을 반환 한 다음 거부에 대한 약속을 뱉어내는 것이 아니라 약속의 콜백 내에서 거부와 해결을 모두 처리하는 것입니다. 예:

async foo(id: string): Promise<A> {
    return new Promise(function(resolve, reject) {
        // execute some code here
        if (success) { // let's say this is a boolean value from line above
            return resolve(success);
        } else {
            return reject(error); // this can be anything, preferably an Error object to catch the stacktrace from this function
        }
    });
}

그런 다음 반환 된 약속에 메소드를 연결하십시오.

async function bar () {
    try {
        var result = await foo("someID")
        // use the result here
    } catch (error) {
        // handle error here
    }
}

bar()

출처-이 튜토리얼 :

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise


답변

여러 try-catch 블록을 사용하지 않고 새로운 접근 방식에서 거부 를 올바르게 처리 할 것을 제안합니다 .

import to from './to';

async foo(id: string): Promise<A> {
    let err, result;
    [err, result] = await to(someAsyncPromise()); // notice the to() here
    if (err) {
        return 400;
    }
    return 200;
}

를 Where to.ts의 기능에서 수입해야한다 :

export default function to(promise: Promise<any>): Promise<any> {
    return promise.then(data => {
        return [null, data];
    }).catch(err => [err]);
}

크레딧은 다음 링크 에서 Dima Grossman으로갑니다 .


답변

이것은 @TJ Crowder의 답변이 아닙니다. 단지 코멘트에 응답하는 코멘트 “그리고 실제로 예외가 거부로 변환 될 경우 실제로 그것이 오류인지 귀찮게할지 확실하지 않습니다. 에러 만 던지는 이유는 아마도 적용되지 않을 것입니다. “

코드에서 async/를 사용하는 경우 await다음 Error대신에 거부하는 것이 좋습니다 400.

try {
  await foo('a');
}
catch (e) {
  // you would still want `e` to be an `Error` instead of `400`
}


답변

나는 이것이 오래된 질문이라는 것을 알고 있지만 스레드를 우연히 발견했으며 여기에 예외 처리를 사용하지 않는 자주 반복되는 조언을 어기 게하는 오류와 거부 사이에 충돌이있는 것 같습니다. 예상 사례를 처리합니다. 설명 : 비동기 메소드가 사용자 인증을 시도하고 인증에 실패한 경우 이는 거부 (예상 된 두 가지 경우 중 하나)이며 오류 (예 : 인증 API를 사용할 수없는 경우)가 아닙니다.

머리카락을 나누지 않았 음을 확인하기 위해이 코드를 사용하여 세 가지 접근 방식에 대한 성능 테스트를 실행했습니다.

const iterations = 100000;

function getSwitch() {
  return Math.round(Math.random()) === 1;
}

function doSomething(value) {
  return 'something done to ' + value.toString();
}

let processWithThrow = function () {
  if (getSwitch()) {
    throw new Error('foo');
  }
};

let processWithReturn = function () {
  if (getSwitch()) {
    return new Error('bar');
  } else {
    return {}
  }
};

let processWithCustomObject = function () {
  if (getSwitch()) {
    return {type: 'rejection', message: 'quux'};
  } else {
    return {type: 'usable response', value: 'fnord'};
  }
};

function testTryCatch(limit) {
  for (let i = 0; i < limit; i++) {
    try {
      processWithThrow();
    } catch (e) {
      const dummyValue = doSomething(e);
    }
  }
}

function testReturnError(limit) {
  for (let i = 0; i < limit; i++) {
    const returnValue = processWithReturn();
    if (returnValue instanceof Error) {
      const dummyValue = doSomething(returnValue);
    }
  }
}

function testCustomObject(limit) {
  for (let i = 0; i < limit; i++) {
    const returnValue = processWithCustomObject();
    if (returnValue.type === 'rejection') {
      const dummyValue = doSomething(returnValue);
    }
  }
}

let start, end;
start = new Date();
testTryCatch(iterations);
end = new Date();
const interval_1 = end - start;
start = new Date();
testReturnError(iterations);
end = new Date();
const interval_2 = end - start;
start = new Date();
testCustomObject(iterations);
end = new Date();
const interval_3 = end - start;

console.log(`with try/catch: ${interval_1}ms; with returned Error: ${interval_2}ms; with custom object: ${interval_3}ms`);

거기에있는 것들 중 일부는 Javascript 인터프리터에 대한 나의 불확실성 때문에 포함되어 있습니다 (한 번에 하나의 토끼 구멍을 내려 가고 싶습니다). 예를 들어 조건부 블록이 최적화되지 않도록 doSomething함수를 포함 하고 반환 값을 할당했습니다 dummyValue.

내 결과는 다음과 같습니다

with try/catch: 507ms; with returned Error: 260ms; with custom object: 5ms

작은 최적화를 찾아내는 데 어려움을 겪을 가치가없는 경우가 많이 있지만 대규모 시스템에서는 이러한 점이 누적 차이를 크게 만들 수 있으며 이는 상당히 큰 비교입니다.

그래서 … 나는 대답이 접근 방식이 비동기 함수 내에서 예측할 수없는 오류를 처리해야한다고 기대하는 경우에 적합하다고 생각하지만 거부가 단순히 “계획 B와 함께 가야한다는 것을 의미하는 경우 (또는 C 또는 D…) “사용자 지정 응답 개체 사용을 거부하는 것이 좋습니다.