本文翻译自:JavaScript Promises - reject vs. throw
I have read several articles on this subject, but it is still not clear to me if there is a difference between Promise.reject
vs. throwing an error. 我已经阅读了几篇关于这个主题的文章,但我仍然不清楚Promise.reject
与抛出错误之间是否存在差异。 For example, 例如,
Using Promise.reject 使用Promise.reject
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
return Promise.reject(new PermissionDenied());
}
});
Using throw 用投掷
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
throw new PermissionDenied();
}
});
My preference is to use throw
simply because it is shorter, but was wondering if there is any advantage of one over the other. 我倾向于使用throw
只是因为它更短,但是想知道是否有一个优于另一个。
#1楼
参考:https://stackoom.com/question/2GKgB/JavaScript承诺-拒绝与抛出
#2楼
Yes, the biggest difference is that reject is a callback function that gets carried out after the promise is rejected, whereas throw cannot be used asynchronously. 是的,最大的区别是reject是一个回调函数,它在promise被拒绝后执行,而throw不能异步使用。 If you chose to use reject, your code will continue to run normally in asynchronous fashion whereas throw will prioritize completing the resolver function (this function will run immediately). 如果您选择使用reject,您的代码将继续以异步方式正常运行,而throw将优先完成解析器功能(此功能将立即运行)。
An example I've seen that helped clarify the issue for me was that you could set a Timeout function with reject, for example: 我见过的一个例子帮助我澄清了问题,你可以设置一个带有拒绝的超时功能,例如:
new Promise(_, reject) {
setTimeout(reject, 3000);
});
The above could would not be possible to write with throw. 以上可能无法用throw写。
In your small example the difference in indistinguishable but when dealing with more complicated asynchronous concept the difference between the two can be drastic. 在你的小例子中,差异无法区分,但在处理更复杂的异步概念时,两者之间的差异可能是极大的。
#3楼
There is no advantage of using one vs the other, but, there is a specific case where throw
won't work. 使用一个与另一个没有任何优势,但是,有一个特定的情况, throw
不起作用。 However, those cases can be fixed. 但是,这些案件可以修复。
Any time you are inside of a promise callback, you can use throw
. 每当你进入promise回调时,你都可以使用throw
。 However, if you're in any other asynchronous callback, you must use reject
. 但是,如果您处于任何其他异步回调中,则必须使用reject
。
For example, this won't trigger the 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 });
Instead you're left with an unresolved promise and an uncaught exception. 相反,你留下了未解决的承诺和未被捕获的异常。 That is a case where you would want to instead use reject
. 在这种情况下,您可能希望改为使用reject
。 However, you could fix this by promisifying the timeout: 但是,你可以通过宣告超时来解决这个问题:
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!' });
#4楼
Another important fact is that reject()
DOES NOT terminate control flow like a return
statement does. 另一个重要的事实是, reject()
如不终止控制流return
的语句一样。 In contrast throw
does terminate control flow. 相比之下, throw
会终止控制流程。
Example: 例:
new Promise((resolve, reject) => { throw "err"; console.log("NEVER REACHED"); }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED"));
vs 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"));
#5楼
TLDR: A function is hard to use when it sometimes returns a promise and sometimes throws an exception. TLDR: 当函数有时返回一个promise并且有时会引发异常时,它很难使用。 When writing an async function, prefer to signal failure by returning a rejected promise 在编写异步函数时,更喜欢通过返回被拒绝的promise来表示失败
Your particular example obfuscates some important distinctions between them: 您的特定示例模糊了它们之间的一些重要区别:
Because you are error handling inside a promise chain, thrown exceptions get automatically converted to rejected promises. 因为你是一个承诺链中的错误处理,抛出的异常都会自动转换为拒绝承诺。 This may explain why they seem to be interchangeable - they are not. 这可以解释为什么它们似乎是可以互换的 - 它们不是。
Consider the situation below: 考虑以下情况:
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')
}
}
This would be an anti-pattern because you would then need to support both async and sync error cases. 这将是一种反模式,因为您需要同时支持异步和同步错误情况。 It might look something like: 它可能看起来像:
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
}
Not good and here is exactly where Promise.reject
( available in the global scope ) comes to the rescue and effectively differentiates itself from throw
. 不好,这正是Promise.reject
(在全球范围内可用)拯救并有效区别于throw
。 The refactor now becomes: 重构现在变成:
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}`
}
})
}
This now lets you use just one catch()
for network failures and the synchronous error check for lack of tokens: 现在,您只需使用一个catch()
进行网络故障, 并使用缺少令牌的同步错误检查:
checkCredentials()
.catch((error) => if ( error == 'No Token' ) {
// do no token modal
} else if ( error === 400 ) {
// do not authorized modal. etc.
}
#6楼
An example to try out. 尝试的一个例子。 Just change isVersionThrow to false to use reject instead of throw. 只需将isVersionThrow更改为false即可使用reject而不是throw。
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) })