이 주제에 대해 여러 기사를 읽었지만 Promise.reject
오류와 던지기 사이에 차이가 있는지는 분명하지 않습니다 . 예를 들어
Promise.reject 사용
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
return Promise.reject(new PermissionDenied());
}
});
던지기 사용하기
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
throw new PermissionDenied();
}
});
내가 선호 throw
하는 것은 더 짧기 때문에 단순히 사용하는 것이지만 다른 것보다 이점이 있는지 궁금합니다.
답변
하나를 사용하는 것의 장점 throw
은 없지만 작동하지 않는 특정한 경우 가 있습니다. 그러나 이러한 경우는 고칠 수 있습니다.
약속 콜백 내부에 있으면 언제든지을 사용할 수 있습니다 throw
. 그러나 다른 비동기 콜백 인 경우을 사용해야합니다 reject
.
예를 들어, 이것은 catch를 트리거하지 않습니다.
new Promise(function() {
setTimeout(function() {
throw 'or nah';
// return Promise.reject('or nah'); also won't work
}, 1000);
}).catch(function(e) {
console.log(e); // doesn't happen
});
대신에 해결되지 않은 약속과 잡히지 않은 예외가 남게됩니다. 대신을 사용하려는 경우 reject
입니다. 그러나 두 가지 방법으로이 문제를 해결할 수 있습니다.
- 제한 시간 내에 원래 약속의 거부 기능을 사용하여 :
new Promise(function(resolve, reject) {
setTimeout(function() {
reject('or nah');
}, 1000);
}).catch(function(e) {
console.log(e); // works!
});
- 타임 아웃을 약속함으로써 :
function timeout(duration) { // Thanks joews
return new Promise(function(resolve) {
setTimeout(resolve, duration);
});
}
timeout(1000).then(function() {
throw 'worky!';
// return Promise.reject('worky'); also works
}).catch(function(e) {
console.log(e); // 'worky!'
});
답변
또 다른 중요한 사실이다 reject()
않습 유사한 제어 흐름을 종료 return
문을 수행합니다. 반대로 throw
제어 흐름은 종료됩니다.
예:
new Promise((resolve, reject) => {
throw "err";
console.log("NEVER REACHED");
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));
vs
new Promise((resolve, reject) => {
reject(); // resolve() behaves similarly
console.log("ALWAYS REACHED"); // "REJECTED" will print AFTER this
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));
답변
예, 가장 큰 차이점은 거부 는 약속이 거부 된 후에 수행되는 콜백 함수이며 throw 는 비동기 적으로 사용할 수 없다는 것입니다. 거부를 사용하도록 선택한 경우 코드는 비동기 방식으로 계속 정상적으로 실행되지만 throw 는 리졸버 기능 완료를 우선 순위로 둡니다 (이 기능은 즉시 실행 됨).
내가 본 문제를 분명히하는 데 도움이되는 예는 다음과 같이 거부로 Timeout 함수를 설정할 수 있다는 것입니다.
new Promise(_, reject) {
setTimeout(reject, 3000);
});
위는 던지기로 쓸 수 없었습니다.
작은 예제에서 구별 할 수없는 차이가 있지만보다 복잡한 비동기 개념을 처리 할 때는 둘 사이의 차이가 극심 할 수 있습니다.
답변
TLDR : 함수는 때때로 약속을 반환하고 때로는 예외를 던질 때 사용하기가 어렵습니다. 비동기 함수를 작성할 때 거부 된 약속을 반환하여 신호 실패를 선호합니다.
귀하의 특정 예는 그들 사이의 중요한 차이점을 모호하게합니다 :
약속 체인 내 에서 오류를 처리하기 때문에 throw 된 예외가 자동으로 변환됩니다. 거부 된 약속 됩니다. 이것은 왜 그들이 상호 교환 가능한 것처럼 보일 수 있는지 설명 할 수 있습니다.
아래 상황을 고려하십시오.
checkCredentials = () => {
let idToken = localStorage.getItem('some token');
if ( idToken ) {
return fetch(`https://someValidateEndpoint`, {
headers: {
Authorization: `Bearer ${idToken}`
}
})
} else {
throw new Error('No Token Found In Local Storage')
}
}
비동기 및 동기화 오류 사례를 모두 지원해야하기 때문에 이것은 안티 패턴입니다. 다음과 같이 보일 수 있습니다.
try {
function onFulfilled() { ... do the rest of your logic }
function onRejected() { // handle async failure - like network timeout }
checkCredentials(x).then(onFulfilled, onRejected);
} catch (e) {
// Error('No Token Found In Local Storage')
// handle synchronous failure
}
좋지 않으며 여기에 정확히 어디에 Promise.reject
(전 세계적으로 이용 가능한) 구출의 와 효과적으로 차별화됩니다 throw
. 리 팩터는 이제 다음과 같습니다.
checkCredentials = () => {
let idToken = localStorage.getItem('some_token');
if (!idToken) {
return Promise.reject('No Token Found In Local Storage')
}
return fetch(`https://someValidateEndpoint`, {
headers: {
Authorization: `Bearer ${idToken}`
}
})
}
이제 catch()
네트워크 장애 및 토큰 부족에 대한 동기 오류 검사에 하나만 사용할 수 있습니다 .
checkCredentials()
.catch((error) => if ( error == 'No Token' ) {
// do no token modal
} else if ( error === 400 ) {
// do not authorized modal. etc.
}
답변
시험해 볼만한 예. throw 대신 거부를 사용하려면 isVersionThrow를 false로 변경하십시오.
const isVersionThrow = true
class TestClass {
async testFunction () {
if (isVersionThrow) {
console.log('Throw version')
throw new Error('Fail!')
} else {
console.log('Reject version')
return new Promise((resolve, reject) => {
reject(new Error('Fail!'))
})
}
}
}
const test = async () => {
const test = new TestClass()
try {
var response = await test.testFunction()
return response
} catch (error) {
console.log('ERROR RETURNED')
throw error
}
}
test()
.then(result => {
console.log('result: ' + result)
})
.catch(error => {
console.log('error: ' + error)
})