【问题标题】:Observable iteration complete event可观察的迭代完成事件
【发布时间】:2016-12-10 09:36:03
【问题描述】:

我正在订阅一个 BehaviorSubject routes$,它会发出一系列方向

例如['left', 'top', 'left']

然后我想以 200 毫秒的延迟记录这个数组的每个元素,现在在记录所有元素之后,我想记录 route finished

我尝试了完整的事件 ()=>{}finally() 运算符,但它们都没有触发,因为 routes$ 仍然存在并且可能会发出新的方向。

/** Stream recent directions */
this.route$.switchMap(() => {
  return Observable
    .interval(200)
    .timeInterval()
    .take(this.route$.getValue().length)
}).subscribe(
  (v) => {
    if (v.value === this.route$.getValue().length) return;
    let i = v.value;
    this.moveStep(this.route$.getValue()[i]);
  }
);

目前我正在使用这种解决方法

.subscribe(
  (v) => {
    if (v.value === this.route$.getValue().length) return;
    let i = v.value;
    this.moveStep(this.route$.getValue()[i]);

    /** Check if it is the last iteration */
    if(i + 1 === this.route$.getValue().length){
      console.log('route finished');
      this.state = PlayerState.Idle;
    }
  }
);

在 observable 中是否有本地方法来实现这一点?

【问题讨论】:

  • 为了清楚起见,你能重写一下吗?

标签: javascript typescript rxjs observable rxjs5


【解决方案1】:

如果我正确理解您要执行的操作,您希望在传递给 BehaviorSubject 的数组已完全迭代并且您只想获取最后一个值时发出一个值。

尽量避免直接在 Observable 链中使用 .getValue(),因为 .getValue() 的内容已经是你应该在链中使用的东西了。

var routes$ = new BehaviorSubject(['default']);

routes$.switchMap((arr) => {
    return Observable.interval(200)
        .take(arr.length)
        .map(i => arr[i])
        .timeInterval()
        .do(null, null, () => console.log('Complete'));
}).subscribe(value => {
    console.log(value);
});

routes$.next(['left', 'top', 'left']);

setTimeout(() => {
    routes$.next(['top', 'right', 'down']);
}, 1000);

这会打印到控制台:

TimeInterval { value: 'left', interval: 208 }
TimeInterval { value: 'top', interval: 241 }
TimeInterval { value: 'left', interval: 207 }
Complete
TimeInterval { value: 'top', interval: 204 }
TimeInterval { value: 'right', interval: 200 }
TimeInterval { value: 'down', interval: 205 }
Complete

观看现场演示:https://jsbin.com/muxasa/5/edit?js,console

注意['default'] 永远不会被重新发送,因为switchMap() 在调用routes$.next(['left', 'top', 'left']); 时会收到一个新数组

【讨论】:

  • 我想以 200 毫秒的延迟记录每个元素,不仅是最后一个,而且我想在记录这些元素时触发一个动作。 (在它遍历数组之后)。你的 jsbin 只记录最后一个值
  • .do 工作,但现在所有元素都被同时记录,我可以在它们之间保持 200 毫秒的延迟吗?
  • @MurhafSousli 你可以do() 但问题是你想在哪里得到通知数组已经完全迭代。您不想在routes$.switchMap(...).subscribe() 中接收它,因为这会使订阅者自动取消订阅()。否则,我建议您重构代码并
  • @MurhafSousli Btw,map()take() 您仍然可以避免在订阅者中使用 .getValue()
【解决方案2】:

如果您的 Observable 尚未完成,您可以使用 debounce() 等待一定时间后再做某事。其他选项是 buffer 您的值按时间/数量,然后在发出缓冲区后执行某些操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-03
    • 1970-01-01
    • 2019-04-09
    • 2015-10-18
    • 2019-03-25
    • 1970-01-01
    相关资源
    最近更新 更多