如何实现支持延迟绑定回调的请求响应类并在请求方法内正确捕获处理错误
看起来你想要的是一套能延迟绑定回调,同时又能在请求发起阶段就提前捕获处理错误的请求/响应类对吧?我来帮你梳理下你的需求和实现思路:
核心需求拆解
你要解决的两个核心问题:
- 允许后续在任意时间通过
handle方法绑定成功/失败回调,不用在发起请求时立刻绑定 - 即使
handle调用得晚,也不能漏掉make方法执行过程中产生的错误,必须在make阶段就能捕获处理这些错误
Version1的局限
你的Version1实现里,make方法直接把fetch后的Promise链传给了Response。如果handle调用不及时,Promise链里的错误可能已经触发但没被捕获,会变成未捕获的Promise rejection,这就是你遇到的痛点——晚调用的handle追不上已经发生的错误。
Version2的解决方案(你的优化思路)
你在Version2里的处理非常巧妙,通过把Promise的最终决议逻辑包装成函数延迟执行,完美解决了问题,我来拆解下这个逻辑:
在
make阶段提前处理流程,但暂停最终决议
在Request的make方法里,先完成fetch、doThing、doAnotherThing的完整流程,遇到错误直接走errorHandler处理。关键是doAnotherThing和errorHandler都返回了一个返回Promise的函数,相当于把最终的成功/失败决议“存”了起来,没有立刻执行。在
handle阶段触发最终决议,绑定回调
到了Response的handle方法里,才会调用这个存起来的函数,真正触发Promise的决议,然后把你传入的成功/失败回调绑定上去。这样不管handle什么时候调用,都能拿到之前已经处理好的结果或错误,不会因为调用晚而漏掉。
完整可运行代码
class Request { make(url, params) { let p = fetch(url, params) .then(this.doThing) .then(this.doAnotherThing) .catch(this.errorHandler); return new Response(p); } doThing(response) { // 这里可以处理原始的fetch响应,比如解析JSON return response.json(); } doAnotherThing(response) { // 这里做自定义的成功处理逻辑 return () => Promise.resolve(response); } errorHandler(error) { // 这里做自定义的错误处理逻辑,比如统一打日志 console.log('请求过程中发生错误:', error); return () => Promise.reject(error); } } class Response { responsePromise; constructor(p) { this.responsePromise = p; } handle(success, failure) { this.responsePromise.then(f => f()) .then(success, failure); } } // 使用示例 const r = new Request(); r.make('https://jsonplaceholder.typicode.com/todos/1', { method: 'GET' }) .handle((res) => console.log('请求成功:', res), (e) => console.error('最终捕获错误:', e));
额外注意点
this指向问题:如果doThing、doAnotherThing这些方法需要访问Request实例的属性,一定要处理this指向。比如在Request的构造函数里绑定this:constructor() { this.doThing = this.doThing.bind(this); this.doAnotherThing = this.doAnotherThing.bind(this); this.errorHandler = this.errorHandler.bind(this); }或者直接把这些方法写成箭头函数,避免
this丢失。支持多次绑定回调:当前实现支持多次调用
handle方法绑定不同的回调,因为每次handle都会重新调用那个存起来的函数,返回一个新的Promise,所有回调都能拿到相同的结果/错误。
备注:内容来源于stack exchange,提问作者Alfredo

