我的问题由两部分组成:
第1部分
根据标准ES6Promise
,我看到我被迫在任何地方使用catch
块,但它看起来像是复制/粘贴,看起来很奇怪。
示例:
我有一些类向后端发出请求(我们称之为API
类(。
我对API
类使用有一些要求
1(我需要在应用程序的不同部分发出请求,单个请求错误处理:
// somewhere...
api.getUser().then(... some logic ...);
// somewhere in another module and in another part of app...
api.getUser().then(... some another logic...);
2(我希望"then"块只有在"getUsers"成功时才能工作。
3(我不想在使用api.getUsers()
的任何地方写入catch
块
api.getUser()
// I don't want following
.catch(e => {
showAlert('request failed');
})
因此,我试图在类内为所有"用户请求"实现单一错误处理
class API {
getUser() {
let promise = makeRequestToGetUser();
promise.catch(e => {
showAlert('request failed');
});
return promise;
}
}
但如果请求失败,我仍然被迫使用catch
块
api.getUser()
.then(... some logic...)
.catch(() => {}) // <- I forced to write it to avoid of “Uncaught (in promise)” warning
否则,我将在控制台中收到"Uncaught(in promise("警告。所以我不知道在我使用api
实例的任何地方如何避免.catch
块。
似乎这是由于在这样的代码中抛出错误:
// This cause "Uncaught error"
Promise.reject('some value').then(() => {});
也许你可以说"只要回到你的课堂上"兑现"承诺"。
class API {
getUser() {
return makeRequestToGetUser().catch(e => {
showAlert('request failed');
return ...
});
}
}
但这与我的#2要求相矛盾。
请参阅此演示:https://stackblitz.com/edit/promises-catch-block-question
所以我的第一个问题是如何在不在我使用api
调用的任何地方写入catch
块的情况下实现所描述的逻辑
第2部分
我检查了具有Q
库的相同API
类实现是否会得到相同的结果,并感到惊讶,因为我没有得到“Uncaught (in promise)” warning
。顺便说一句,这比原生ES6 Promises的行为更令人期待。
在此页面中https://promisesaplus.com/implementations我发现Q
库是Promises/A+规范的实现。但为什么它有不同的行为?es6 promise是否尊重Promises/A+规范?
有人能解释为什么这些库有不同的行为,哪一个是正确的,以及在"ES6-Promises实现"正确的情况下如何实现所提到的逻辑吗?
我看到我被迫在的所有地方使用catch块
不,你不需要这么做。相反,将then
创建的promise返回给调用者(以及该调用者的调用者,以及…(。在最高层处理错误(例如,启动调用序列的事件处理程序(。
如果对您来说catch
仍然太多,您可以挂接unhandledrejection
事件并阻止其默认值:
window.addEventListener('unhandledrejection', event => {
event.preventDefault();
// You can use `event.reason` here for the rejection reason, and
// `event.promise` for the promise that was rejected
console.log(`Suppressed the rejection '${event.reason.message}'`);
});
Promise.reject(new Error("Something went wrong"));
浏览器将在控制台中报告未处理的拒绝之前触发该事件。
Node.js也支持这一点,在process
对象上:
process.on('unhandledRejection', error => {
// `error` is the rejection reason
});
请注意,您可以直接获得原因,而不是作为事件对象的属性。
所以我不知道如何在我使用
api
实例的任何地方避免.catch
块。
getUser
的调用者肯定需要知道它失败了吗?我的意思是,如果答案真的是"不,他们不",那么事件就是前进的道路,但实际上使用api
的代码应该是这样的:
function useTheAPI() {
return getUser()
.then(user => {
// Do something with user
});
}
(或等效的async
(,使得调用useTheAPI
的代码知道发生了错误;同样,只有顶层才需要实际处理错误。
有人能解释为什么这些库有不同的行为,哪一个是正确的,以及在"ES6-Promises implementation"正确的情况下如何实现上述逻辑吗?
两者都是正确的。完全在userland(图书馆所在地(报告未处理的异常是很难做到的,甚至是不可能做到的,这样就不会出现误报。JavaScript引擎可以将其作为垃圾收集的一部分来执行(例如:如果没有任何内容再引用promise,并且它被拒绝,并且没有任何内容处理该拒绝,则发出警告(。