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.
});
}
이 경우 어떻게이 약속을 올바르게 거절 할 수 있습니까?
답변
가장 좋은 방법이다 포장 값와 거부 약속의 결과 포장 값 :throw
Error
Error
} 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
소비하는 모든 것과 잘 어울 립니다.foo
await
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…) “사용자 지정 응답 개체 사용을 거부하는 것이 좋습니다.