可观察对象的订阅中的最终操作

177
根据这篇文章subscribeonCompleteonError函数是互斥的。
这意味着无论我在subscribe中接收到错误还是成功完成信息流,只会触发一个onErroronComplete事件。
我有一个逻辑块需要被执行,无论我是否收到错误或成功完成信息流。
我查找类似于Python中的finally的东西,但我找到的都是需要附加到我创建的observable上的finally
但是我想在订阅后,当流已经结束,无论成功还是出现错误,只执行那个逻辑块。
有什么想法吗?
3个回答

200

这个操作符的当前“可管道化(pipable)”变体被称为finalize()(自 RxJS 6 开始)。旧版本且现已弃用的“patch”操作符称为finally()(直到 RxJS 5.5)。

我认为finalize()操作符实际上是正确的。您说:

只有当我订阅时并且流已经结束时才执行该逻辑

我认为这不是问题。如果您想要一个单一的source并在订阅之前使用finalize(),这样您就不需要总是使用finalize()

let source = new Observable(observer => {
  observer.next(1);
  observer.error('error message');
  observer.next(3);
  observer.complete();
}).pipe(
  publish(),
);

source.pipe(
  finalize(() => console.log('Finally callback')),
).subscribe(
  value => console.log('#1 Next:', value),
  error => console.log('#1 Error:', error),
  () => console.log('#1 Complete')
);

source.subscribe(
  value => console.log('#2 Next:', value),
  error => console.log('#2 Error:', error),
  () => console.log('#2 Complete')
);

source.connect();

这会在控制台打印:

#1 Next: 1
#2 Next: 1
#1 Error: error message
Finally callback
#2 Error: error message

2019年1月:已更新至RxJS 6版本


1
有趣的是,它与 Promises 的模式相反,因为 finally() 方法首先被附加,而订阅在命令式地强制执行通过/失败。 - BradGreens
9
是的,这太糟糕了。人们本以为你的代码中finally块会最后执行。 - d512
1
我喜欢Angular JS的Promise系统...正如d512所说,我期望"finally"是最后一个...一点也不喜欢这个... - Sampgun
11
从 RXJS 5.5 开始,“finally”不再是 Observable 的方法。请使用“finalize”操作符代替:source.pipe(finalize(() => console.log('Finally callback'))).subscribe(...); 参考链接 https://github.com/ReactiveX/rxjs/blob/master/doc/pipeable-operators.md - Stevethemacguy
3
finalize 的问题在于它等待 "complete()" 调用。如果你想在每个发射事件上都有一个 finally (如果可观察的发射事件成功,执行 _a_,如果出错,则执行 b .. 在这两种情况下,都要执行 c),该怎么办呢? - roberto tomás
@robertotomás finalize 等待 complete() 或 error() (https://rxjs.dev/api/operators/finalize)。 - santos

144

对我有效的唯一方法是这个

fetchData()
  .subscribe(
    (data) => {
       //Called when success
     },
    (error) => {
       //Called when error
    }
  ).add(() => {
       //Called when operation is complete (both success and error)
  });

我使用这个来获取表格数据,在删除文件订阅后,它像魔法一样运行良好,谢谢! - borgmater
你知道这个是否也能不在subscribe方法中加入任何内容而直接使用,例如.subscribe().add(() => {})吗? - Raphaël Balet
如果在它完成之前取消订阅,它就不起作用。我会选择被接受的答案,它没有这个问题。 - Raphaël Balet

38

我现在在一个Angular应用中使用RxJS 5.5.7,并且在我的用例中使用finalize操作符会有奇怪的行为,因为它在成功或错误回调之前被触发。

以下是一个简单的例子:

// Simulate an AJAX callback...
of(null)
  .pipe(
    delay(2000),
    finalize(() => {
      // Do some work after complete...
      console.log('Finalize method executed before "Data available" (or error thrown)');
    })
  )
  .subscribe(
      response => {
        console.log('Data available.');
      },
      err => {
        console.error(err);
      }
  );

我不得不使用订阅中的add方法来完成我想要的操作。基本上,在成功或错误回调完成后,需要一个finally回调。就像try..catch..finally块或Promise.finally方法一样。

简单示例:

// Simulate an AJAX callback...
of(null)
  .pipe(
    delay(2000)
  )
  .subscribe(
      response => {
        console.log('Data available.');
      },
      err => {
        console.error(err);
      }
  )
  .add(() => {
    // Do some work after complete...
    console.log('At this point the success or error callbacks has been completed.');
  });

4
这个回答发布以后,finalize操作符肯定已经改变了。根据你发布的代码显示finalize操作符被过早地调用,对我而言它正如预期一样工作。 - wizloc

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接