Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angular/29.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Angular RXJS如何知道Finalize何时完成?_Angular_Rxjs_Observable_Order Of Execution - Fatal编程技术网

Angular RXJS如何知道Finalize何时完成?

Angular RXJS如何知道Finalize何时完成?,angular,rxjs,observable,order-of-execution,Angular,Rxjs,Observable,Order Of Execution,我对RXJS比较陌生,所以如果这是重复的话,我很抱歉。我试图搜索答案,但找不到任何答案,可能是因为我不知道该使用哪个搜索词 我试图理解如何知道服务调用的finalize块何时完成,因为它更新了一个共享状态变量 下面是它的stackblitz,不过我也会在下面发布一些片段: 我有一个Angular应用程序,其服务将sharedisLoading标志设置为true,启动HTTP请求,然后使用finalize将isLoading标志设置回false,这样无论成功与否,检查isLoading标志的项目知

我对RXJS比较陌生,所以如果这是重复的话,我很抱歉。我试图搜索答案,但找不到任何答案,可能是因为我不知道该使用哪个搜索词

我试图理解如何知道服务调用的finalize块何时完成,因为它更新了一个共享状态变量

下面是它的stackblitz,不过我也会在下面发布一些片段:

我有一个Angular应用程序,其服务将shared
isLoading
标志设置为true,启动HTTP请求,然后使用
finalize
isLoading
标志设置回false,这样无论成功与否,检查
isLoading
标志的项目知道HTTP请求不再处理

我已将该场景简化为单独的方法,而不是单独的类:

isLoading = false;

public ngOnInit() {
  this.serviceCall().subscribe(
    next => {
      console.log("value of isLoading in next handler: " + this.isLoading);
    },
    err => {
      console.log("value of isLoading in error handler: " + this.isLoading);
    },
    () => {
      console.log("value of isLoading in complete handler: " + this.isLoading);
    }
  );
}

private serviceCall() {
  this.isLoading = true;
  return this.httpCall().pipe(
    tap(value => console.log(value)),
    finalize(() => {
      this.isLoading = false;
      console.log("Value of isLoading in serviceCall finalize: " + this.isLoading);
    })
  );
}

private httpCall() {
  return new Observable(subscriber => {
    console.log("Starting emissions");
    subscriber.next(42);
    subscriber.next(100);
    subscriber.next(200);
    console.log("Completing emissions");
    subscriber.complete();
  });
}
我惊讶地发现这个例子的输出是

开始排放

42

下一个处理程序中isLoading的值:true

一百

下一个处理程序中isLoading的值:true

二百

下一个处理程序中isLoading的值:true

完成排放

完整处理程序中isLoading的值:true

serviceCall finalize中isLoading的值:false

为什么在
ngOnInit
的subscribe块的完整处理程序之后调用
serviceCall
finalize
?如果不是通过已完成的处理程序,
serviceCall
何时完成了对共享变量的操作,我又怎么知道呢?

关于
finalize
这取决于如何实现
finalize
。我同意这可能不是很直观。我是一个分裂派别的一部分,该派别相信现在的实施方式是直觉的方式

考虑一个在发射任何东西之前未被订阅的可观测对象。我希望finalize仍然会触发,但我不希望向我的观察者发送
完整的
通知

一个六个,另一个半打

通常,流发生的最后一件事是它被取消订阅。取消订阅流时调用Finalize。这在完全或错误发射后发生

你可以把finalize想象成在拆除一个可观察物体的过程中发生的事情。而观察者正在观察仍然存在的可观察物的发射


尽可能避免副作用 通常,设置全局变量并稍后在同一
管道中检查这些变量等副作用被视为代码气味。相反,如果您更加努力地学习RxJS streams提倡的功能性方法,那么类似的问题应该会消失


旁白: 对异步事件进行计时通常会导致奇怪或意外的结果(如果可以的话,部分原因是您确实不应该手动实现这种事情)

考虑一下当我向您的流中添加延迟时会发生什么:

private serviceCall(){
this.isLoading=true;
返回此.httpCall().pipe(
点击(值=>console.log(值)),
完成(()=>{
this.isLoading=false;
log(“serviceCall finalize中isLoading的值:“+this.isLoading”);
}),
延迟(0)
);
}
您可能会认为0毫秒的延迟应该没有什么区别,但是因为每个延迟都被放到JS的微任务队列中,所以您会注意到代码运行方式的显著差异。在使用第一个值调用subscribe之前,
isLoading
将已为false

这是因为延迟之前的一切都是同步运行的,并且将在微任务队列运行之前完成。延迟(0)
之后的所有操作都是异步运行的,并将在下次JS准备运行微任务队列时完成


最小阻力解 这不是惯用的RxJS,但在本例中,它将以您期望的方式工作

您可以使用tap操作符捕捉
完成的发射。由于点击将在
complete
时触发,因此应在
subscribe
之前触发,因此适用于您的用例

函数serviceCall(){
const setIsLoading=bool=>(=null)=>this.isLoading=bool;
返回延迟(()=>{
设置加载(真)();
返回此.httpCall().pipe(
水龙头({
下一步:console.log,
错误:setIsLoading(错误),
完成:设置加载(错误)
})
);
});
}

感谢您帮助我了解finalize的本质!但是,使用您提供的解决方案,我不再获得finalize块所带来的好处,即在成功和错误情况下更新isLoading值。如果我调整您的解决方案,使管道还包含一个catchError,该catchError的代码与清除标志并重新抛出错误的代码相同,那么我将有一个完整的解决方案。虽然与最终定稿相比,它看起来很混乱。我确实想解决代码的味道,但现在我只关注将AngularJS转换为AngularJS,没有太多的逻辑更改。你也可以在tap操作符中看到错误,这是值得的(你不能处理它们,但如果你愿意,可以在其他地方这样做)。我已经为您更新了解决方案。实际上,再快速更新一次,您可能希望在订阅
serviceCall()
时而不是调用时设置
this.isLoading=true
。根据以后serviceCall()的组成方式,您可以在订阅之前很长一段时间创建可观察对象(例如,与
concat
运算符通用)
Defer
在订阅后只需调用其工厂函数,因此它是解决该问题的快速方法。