JavaScript Promises - 拒绝与抛出
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33445415/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
JavaScript Promises - reject vs. throw
提问by Naresh
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. For example,
我已经阅读了几篇关于这个主题的文章,但我仍然不清楚Promise.reject
与抛出错误之间是否存在差异。例如,
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
简单地使用它,因为它更短,但想知道是否有任何优势。
采纳答案by Kevin B
There is no advantage of using one vs the other, but, there is a specific case where throw
won't work. However, those cases can be fixed.
使用一个和另一个没有任何优势,但是,有一种特定的情况是throw
行不通的。但是,这些情况是可以修复的。
Any time you are inside of a promise callback, you can use throw
. However, if you're in any other asynchronous callback, you must use reject
.
任何时候您处于 Promise 回调中,您都可以使用throw
. 但是,如果您处于任何其他异步回调中,则必须使用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
. However, you could fix this in two ways.
相反,您会留下一个未解决的承诺和一个未捕获的异常。在这种情况下,您希望改为使用reject
. 但是,您可以通过两种方式解决此问题。
- by using the original Promise's reject function inside the timeout:
- 通过在超时内使用原始 Promise 的拒绝函数:
new Promise(function(resolve, reject) {
setTimeout(function() {
reject('or nah');
}, 1000);
}).catch(function(e) {
console.log(e); // works!
});
- 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!'
});
回答by lukyer
Another important fact is that reject()
DOES NOTterminate control flow like a return
statement does. In contrast throw
does terminate control flow.
另一个重要的事实是,reject()
并不像一个终止控制流return
语句一样。相反,throw
确实会终止控制流。
Example:
例子:
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"));
回答by Blondie
Yes, the biggest difference is that rejectis a callback function that gets carried out after the promise is rejected, whereas throwcannot be used asynchronously. If you chose to use reject, your code will continue to run normally in asynchronous fashion whereas throwwill prioritize completing the resolver function (this function will run immediately).
是的,最大的区别是拒绝是在承诺被拒绝后执行的回调函数,而throw不能异步使用。如果您选择使用拒绝,您的代码将继续以异步方式正常运行,而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.
在您的小示例中,无法区分的差异但是在处理更复杂的异步概念时,两者之间的差异可能很大。
回答by maxwell
TLDR:A function is hard to use when it sometimes returns a promise and sometimes throws an exception. When writing an async function, prefer to signal failure by returning a rejected promise
TLDR:当函数有时返回承诺有时抛出异常时,它很难使用。编写异步函数时,更喜欢通过返回被拒绝的承诺来表示失败
Your particular example obfuscates some important distinctions between them:
您的特定示例混淆了它们之间的一些重要区别:
Because you are error handling insidea promise chain, thrown exceptions get automatically convertedto 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
. The refactor now becomes:
不好,这正是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}`
}
})
}
This now lets you use just one catch()
for network failures andthe 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.
}
回答by Chris Livdahl
An example to try out. Just change isVersionThrow to false to use reject instead of 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)
})