Promise、Observable.fromPromise()及订阅中的错误捕获疑问
解答你的RxJS与Promise转换问题
问题1:如何让catch中的错误流到订阅的onError方法里?
你当前在catch里返回rx.Observable.of(error),这相当于把错误事件转换成了普通的next事件,所以订阅时会在onNext回调里收到这个error对象,而不会触发onError。
如果想让错误直接传递到订阅的onError,你需要在catch里返回rx.Observable.throw(error)(如果是RxJS 6及以上版本,要用throwError,但看你的代码用的是rx.Observable,应该是旧版本,所以用Observable.throw)。修改后的代码如下:
const observableItem = { id: target.id, observable$: rx.Observable .fromPromise(getPromise(target)) .catch((error) => { // 直接抛出错误,让它流到订阅的onError回调 return rx.Observable.throw(error); }) };
这样修改后,订阅的onError(也就是你代码里的[2]处)就会收到这个错误,你就不用在onNext里判断payload是否包含error了,代码逻辑会更清晰。
问题2:各类错误该在catch还是onError处理?
先帮你理清不同错误的流向:
- 连接超时、ENOTFOUND:这些属于网络层错误,会触发
request回调的error参数,你的Promise会调用reject,所以这些错误会进入fromPromise之后的catch操作符。你可以选择在catch里统一处理(比如加日志、转换错误格式),也可以不在catch里拦截,让它们直接流到订阅的onError里处理。 - 404错误:当前你的Promise里,只有
request的error才会触发reject,但404是HTTP状态码,属于服务器正常返回的响应(只是状态不对),所以你的Promise会调用resolve,把结果传到订阅的onNext里。如果想让404也进入错误流,你需要修改Promise,在收到非2xx状态码时也调用reject,比如:
const getPromise = (target) => { return new Promise((resolve, reject) => { request( { url: url, json: true }, (error, response, body) => { if (error) { reject({ id: target.id, error: error, response: response, body: body }); } else if (response.statusCode >= 400) { // 新增:判断HTTP状态码是否为错误码 reject({ id: target.id, error: `HTTP Error: ${response.statusCode}`, response: response, body: body }); } else { resolve({ id: target.id, body: body }); } }); }); };
处理策略建议:
- 如果需要在数据流的中间统一处理错误(比如给所有错误添加统一的日志,或者转换错误结构),就在
catch操作符里处理; - 如果需要针对每个Observable的错误做个性化处理(比如不同target的错误处理逻辑不同),就在订阅的
onError回调里处理; - 对于HTTP状态码类的错误,建议先修改Promise把它们转为reject,这样就能和网络错误一样进入错误流,实现统一的错误处理逻辑。
内容的提问来源于stack exchange,提问作者stashko
相关产品推荐
相关产品推荐

