JavaScript的承诺 – 拒绝与抛出
我已经阅读了关于这个主题的几篇文章,但是我还不清楚Promise.reject
和抛出一个错误是否有区别。 例如,
使用Promise.reject
return asyncIsPermitted() .then(function(result) { if (result === true) { return true; } else { return Promise.reject(new PermissionDenied()); } });
使用throw
return asyncIsPermitted() .then(function(result) { if (result === true) { return true; } else { throw new PermissionDenied(); } });
我的select是使用throw
因为它更短,但想知道是否有优势。
使用一个和另一个没有什么优势,但是,有一个特殊的情况下throw
不行。 但是,这些情况可以修复。
任何时候你在一个承诺callback里面,你都可以使用throw
。 但是,如果您使用其他asynchronouscallback,则必须使用reject
。
例如,
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()
不会像return
语句那样终止控制stream。 相反, throw
会终止控制stream。
例:
new Promise((resolve, reject) => { throw "err"; console.log("NEVER REACHED"); }) .then(() => console.log("RESOLVED")) .catch(() => console.log("REJECTED"));
是的,最大的不同在于, 拒绝是一个callback函数,在承诺被拒绝后执行,而throw不能asynchronous使用。 如果您select使用拒绝,您的代码将继续以asynchronous方式正常运行,而throw将优先完成parsing器function(此函数将立即运行)。
我见过的一个例子帮助我澄清了这个问题,就是您可以用拒绝来设置Timeout函数,例如:
new Promise(_, reject) { setTimeout(reject, 3000); });
以上可能无法用throw来写。
在你的小例子中,差别是难以区分的,但是当处理更复杂的asynchronous概念时,两者之间的差异可能是激烈的。
TLDR: 当函数有时返回一个promise,有时会抛出一个exception,这个函数很难使用。 在编写asynchronous函数时,更愿意通过返回被拒绝的承诺来表示失败
您的具体例子混淆了它们之间的一些重要区别:
由于您在承诺链内进行error handling,因此抛出的exception会自动转换为拒绝的承诺。 这可以解释为什么他们似乎是可以互换的 – 他们不是。
考虑下面的情况:
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') } }
这将是一种反模式,因为您需要同时支持asynchronous和同步错误情况。 它可能看起来像这样:
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()
来检测networking故障,同时检查缺less令牌的同步错误:
checkCredentials() .catch((error) => if ( error == 'No Token' ) { // do no token modal } else if ( error === 400 ) { // do not authorized modal. etc. }