我正在最新的Angular 6上构建体系结构,而来自AngularJS的事情让我无法安心:HTTP请求的基本处理。
因此,出于问题的原因,假设我想要一个可观察的对象。因为这似乎是Angular的未来。
我是从AngularJS的一个非常优雅的东西开始的:
service.getAll()
.then(onSuccess) // I process the data
.catch(onError) // I do whatever needed to notify anyone about the issue
.finally(onFinally); // I stop the loading spinner and other stuff
现在在Angular 6 / RxJS 6中,我不明白为什么一切都如此复杂并且看起来不正确。
我可以找到两种方法来完成上述工作:
完整管道
this.service.getAll()
.pipe(
map((data) => this.onSuccess(data)),
catchError(error => of(this.handleError(error))),
finalize(() => this.stopLoading())
)
.subscribe();
由于我们必须使用pipe进行终结处理,因此我不妨对所有内容都使用pipe,我认为最好将所有内容按相同顺序进行。但是现在我们必须扔一些东西,叫做“ of”(不是很容易理解),我不喜欢这样。
半管 因此,我尝试了另一个想法,只用了我需要的管道(完成),并保留了订阅回调。
this.service.getAll()
.pipe(
finalize(() => this.stopLoading())
)
.subscribe(
(data) => this.onSuccess(data),
(error) => this.handleError(error)
);
但是,很好。是不是有点落后了?我们仍然有没有实际名称的回调,并且在读取处理和错误之前完成确定。很奇怪。
所以我绝对不了解某些内容。而且我在网上找不到与此基本问题相关的任何内容。您要么有人想要“成功并最终”,要么有人想要“成功与错误”,但是没人想要其中的三个。 也许我年纪太大了,我不了解关于它的最新最佳实践(如果是,请教育我!)。
我的需求很简单:
1.我要处理从服务获得的数据
2.我想获取错误以便显示给用户
3.我想停止在呼叫之前刚开始的加载微调器,或者在第一个呼叫成功或失败后再打另一个呼叫(我真的想要一个最终的呼叫)
如何使用可观察的方式处理基本的HTTP调用?
(请不要,我不需要任何.toPromise
,我想了解如何处理新内容)
答案 0 :(得分:19)
我认为有一个关键的误解:
您要么有人想要“成功并最终”,要么有人想要“成功与错误”,但没人想要其中的三个。
这并非完全正确。每个Observable可以发送零个或多个next
通知和一个error
或complete
通知,但不能同时发送。例如,当成功进行HTTP调用时,您将收到一个next
和一个complete
通知。根据错误的HTTP请求,您将只有一个error
通知,仅此而已。参见http://reactivex.io/documentation/contract.html
这意味着您永远不会发射error
和complete
的Observable。
然后是finalize
运算符。处置链时(包括普通的取消订阅),将调用此运算符。换句话说,它在error
和complete
通知之后称为之后。
因此,第二个示例是正确的。我了解您在订阅之前加入finalize
看起来很奇怪,但是实际上来自Observable来源的每个发射都从上到下先到达订阅者,然后发出error
或complete
通知它触发处理程序处理程序从下至上(以相反顺序),并在此时调用finalize
。参见https://github.com/ReactiveX/rxjs/blob/master/src/internal/Subscriber.ts#L150-L152
在您的示例中,使用finalize
与自己将处置处理程序添加到Subscription
对象中相同。
const subscription = this.service.getAll()
.subscribe(
(data) => this.onSuccess(data),
(error) => this.handleError(error)
);
subscription.add(() => this.stopLoading());
答案 1 :(得分:4)
Observable的subscribe
方法接受3个可选函数作为参数
因此,如果我理解正确,则可以使用如下所示的代码实现所需的目标
this.service.getAll()
.subscribe(
data => this.onSuccess(data),
error => this.handleError(error),
() => this.onComplete()
);
请考虑使用http:// observables进行调用可以在遇到争用情况时重试(请参阅retry
运算符)(通过使用switchMap
运算符)。我认为这是Angular团队为http客户端选择这种方法的主要原因。
总的来说,我认为值得一开始了解Observables和一些最重要的运算符的工作方式(除了上述运算符之外,我首先考虑mergeMap
,filter
,{{1 }}-但是还有很多其他内容很重要),因为它们可以大大简化异步非阻塞环境中的许多任务,例如浏览器(例如Node)。
答案 2 :(得分:1)
我认为正确的方法是使用Observable函数:next,err,complete。
这是如何触发完整功能的示例。
假设我们有BehaviorSubject对象:
let arr = new BehaviorSubject<any>([1,2]);
现在让我们假设我们要订阅它,并且如果我们获得值“ finish”,我们就想完成。
let arrSubscription = arr.asObservable().subscribe(
data => {
console.log(data)
if(data === 'finish') {
arr.complete()
}
},
err => {
console.log(err)
},
() => {
console.log("Complete function triggered.")
}
);
arr.next([3,4])
arr.next('finish')
arr.next([5,6])
控制台日志为:
[1,2]
[3,4]
finish
Complete function triggered.
由于我们触发了complete函数,因此不会触发BehaviorSubject的最后一个.next,因为err和complete函数是订阅的终止符。
这只是一个示例,说明您如何触发完整功能,从这里您可以执行所需的任何操作。