我读过几篇关于这个主题的文章,但我仍然不清楚《承诺》和《承诺》之间是否有区别。拒绝与抛出错误。例如,
使用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,因为它更短,但我想知道其中一种比另一种是否有任何优势。
另一个重要的事实是reject()不会像return语句那样终止控制流。相反,throw会终止控制流。
例子:
new Promise((resolve, reject) => {
把“犯错”;
console.log(“从来没有达到”);
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));
vs
new Promise((resolve, reject) => {
拒绝();// resolve()行为类似
console.log(“总是达到“);// "REJECTED"将在此之后打印
})
.then(() => console.log("RESOLVED"))
.catch(() => console.log("REJECTED"));
TLDR:当函数有时返回承诺,有时抛出异常时,它很难使用。在编写异步函数时,最好通过返回一个被拒绝的承诺来表示失败
你的例子混淆了它们之间的一些重要区别:
因为您是在承诺链内进行错误处理,抛出的异常会自动转换为被拒绝的承诺。这也许可以解释为什么它们看起来是可以互换的——实际上并非如此。
考虑以下情况:
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
}
不太好,这正是承诺。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将不起作用。然而,这些情况是可以解决的。
任何时候在promise回调中,都可以使用throw。然而,如果你在任何其他异步回调中,你必须使用拒绝。
例如,这不会触发catch:
新承诺(函数(){
setTimeout(函数(){
抛出'or nah';
// return承诺。拒绝(或不);也不管用
}, 1000);
}) .catch(函数(e) {
console.log (e);//不会发生
});
相反,留给您的是一个未解决的承诺和一个未捕获的异常。在这种情况下,您应该使用reject。但是,您可以通过两种方式解决这个问题。
通过在超时内使用原来的Promise的拒绝函数:
new Promise(function(resolve, reject) {
setTimeout(function() {
拒绝(“或否”);
}, 1000);
}).catch(function(e) {
控制台.log(e);工程!
});
通过承诺超时:
function timeout(duration){//谢谢joews
返回新的承诺(函数(resolve) {
setTimeout(解决,持续时间);
});
}
超时(1000)(函数(){
把“成功!”;
// return Promise.reject('work ');同样适用
}) .catch(函数(e) {
console.log (e);/ /“成功!”
});
是的,最大的区别是reject是在promise被拒绝后执行的回调函数,而throw不能异步使用。如果你选择使用reject,你的代码将继续以异步方式正常运行,而throw将优先完成解析器函数(该函数将立即运行)。
我看到的一个例子帮助我澄清了这个问题,你可以用reject设置Timeout函数,例如:
新承诺(兑现,兑现)=>
setTimeout() = >{拒绝(“err味精);控制台日志。(‘吃’)的,1000);
回收回路(“后悔”)
})
然后(o) => console.log(“RESOLVED”,o)
.catch(o) => console.log(“reject”,o);
上面的代码不能用throw来写。
尝试{
new Promise((resolve, reject) => {
setTimeout(()=>{抛出新的错误('err msg')}, 1000);
返回resolve('ret val')
})
.then((o) => console.log("RESOLVED", o))
.catch((o) => console.log("REJECTED", o));
}捕捉(o) {
console.log(“忽略”,o)
}
在OP的小例子中,差异是难以区分的,但当处理更复杂的异步概念时,两者之间的差异可能是巨大的。