我的问题包括两个部分:
根据标准ES6 Promise
,我看到我不得不在所有地方都使用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)我不想在使用catch
的任何地方写api.getUsers()
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
...否则,我将在控制台中收到“未捕获(承诺)”警告。因此,我不知道在使用.catch
实例的任何地方如何避免api
阻塞的方式。
这似乎是由于在此类代码中引发错误而引起的:
// 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/js-xqwiq1?file=index.js
因此,我的第一个问题是如何在不使用catch
调用的任何地方编写api
块而实现描述的逻辑?
我检查了与API
库相同的Q
类实现是否会得到相同的结果,并且感到惊讶,因为我没有得到“Uncaught (in promise)” warning
。顺便说一句,它比本地ES6 Promises的行为更值得期待。
观看此演示https://stackblitz.com/edit/js-g6efg5
在此页面https://promisesaplus.com/implementations中,我发现Q
库是Promises / A +规范的实现。但是为什么会有不同的行为呢?
es6承诺遵守Promises / A +规范吗?
谁能解释为什么这些库具有不同的行为,哪一个是正确的,以及在“ ES6 Promises实现”正确的情况下如何实现所提到的逻辑?
答案 0 :(得分:1)
我发现我被迫在各处使用catch块
不,您不需要这样做。而是将then
创建的承诺返回给呼叫者(以及该呼叫者的呼叫者,以及...)。在可用的最高级别上处理错误(例如,启动调用序列的事件处理程序)。
如果您仍然需要太多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
});
请注意,您直接获得原因而不是作为事件对象的属性。
所以我不知道在使用
.catch
实例的任何地方如何避免api
阻塞。
肯定getUser
的调用者需要知道它失败了吗?我的意思是,如果对此的答案确实是“否,那么他们不是”,那么该事件就是解决方法,但实际上使用api
的代码应如下所示:
function useTheAPI() {
return getUser()
.then(user => {
// Do something with user
});
}
(或等效的async
),以便调用useTheAPI
的代码知道发生了错误;再一次,只有顶层需要实际处理错误。
谁能解释为什么这些库具有不同的行为,哪一个是正确的,以及在“ ES6 Promises实现”正确的情况下如何实现所提到的逻辑?
两个都是正确的。完全不可能在用户区(库所在的地方)报告未处理的异常,这样就不会出现误报。 JavaScript引擎可以将其作为垃圾回收的一部分来进行处理(例如:如果不再有任何对诺言的引用,并且诺言被拒绝,并且没有人处理该诺言,则发出警告)。