Javascript 如何在rxjs中组合Scheduler.animationFrame和fromEvent(窗口、滚动和)流?

Javascript 如何在rxjs中组合Scheduler.animationFrame和fromEvent(窗口、滚动和)流?,javascript,rxjs,observable,requestanimationframe,Javascript,Rxjs,Observable,Requestanimationframe,我有两个可观察的Observable.of(0,animationFrame)和Observable.fromEvent(窗口“滚动”)。我想将它们组合起来,这样我的renderScrollBar(event)只在animationFrame的刻度上被调用 Observable.fromEvent(window, 'scroll') .map((event: any) => event.currentTarget) .subscribe((event) =>

我有两个可观察的
Observable.of(0,animationFrame)
Observable.fromEvent(窗口“滚动”)
。我想将它们组合起来,这样我的
renderScrollBar(event)
只在animationFrame的刻度上被调用

  Observable.fromEvent(window, 'scroll')
      .map((event: any) => event.currentTarget)
      .subscribe((event) => {
        this._renderScrollBar(event);
      });
  let x = 0;
  Observable.of(0, animationFrame)
      .repeat()
      .takeUntil(Observable.timer(1000))
      .subscribe(() => console.log(x++));
}
是一个快速而肮脏的解决方案,它有一个潜在的严重缺陷:当滚动事件发出的速度超过帧速率时,滚动处理程序滞后于真正的滚动值。它看起来像:

Observable.fromEvent(window, 'scroll')
          .map(event => event.currentTarget)
          .zip(Observable.of(0, animationFrame)
                         .repeat(),
            (currentTarget, _) => this._renderScrollBar(currentTarget)
          );
如果您需要
event
来包含最新的滚动信息,您可能需要求助于更复杂的解决方案,例如:

  • 最重要的是,
    window
    从源代码创建一个可观察的块流,每次可观察的参数发出一个项时都会进行块。在这种情况下,一系列滚动事件由每个动画标记分块
  • 如果块不是空的,我们只从每个块中获取最新的,并将其映射到平面输出流。空块不会向最终流贡献任何项

  • 如果要将滚动事件限制到requestAnimationFrame,可以使用
    throttleTime(0,animationFrame)
    操作符,而不是
    Observable.of(0,animationFrame)

    范例

    Observable.fromEvent(window, 'scroll')
        .throttleTime(0, animationFrame)
    
    更新:

    RxJS 6

    import { fromEvent, animationFrameScheduler } from "rxjs";
    import { throttleTime } from "rxjs/operators";
    
    fromEvent(window, "scroll")
      .pipe(throttleTime(0, animationFrameScheduler))
    
    无论我们设定的时间是1秒、2秒还是100秒,这两个似乎只差1帧;)


    我不认为有任何简单的方法可以在RxJS中的每个动画帧上运行动作。你想要的是行为吗?@concat我想是的,你能在答案中制作一个示例吗?我会尝试一下,并将其标记为正确。它似乎正常工作,但我得到一个错误EmptyError{name:“EmptyError”,stack:“EmptyError:序列中没有元素,message:“序列中没有元素”}message:“序列中没有元素”name:“EmptyError”stack:“EmptyError:序列中没有元素”sequence@MatthewHarwood我的坏,
    takeLast(1)
    是您想要的,因为它不会抛出空流。我建议将其更新到RXJS 6,但回答很好。这个答案帮助我最终修复了一个困扰我们几个月、几乎无法追踪的错误!非常感谢。我们将
    throttleTime
    操作符放在更下游的位置,而不是正好在
    fromEvent
    之后,不知何故,这把事情搞砸了。如果您对沉默时间窗口中的最新事件感兴趣,而不是第一个事件,然后我建议使用
    auditTime
    操作符,而不是
    throttleTime
    import { fromEvent, animationFrameScheduler } from "rxjs";
    import { throttleTime } from "rxjs/operators";
    
    fromEvent(window, "scroll")
      .pipe(throttleTime(0, animationFrameScheduler))
    
    interval(0)
      .pipe(throttleTime(0, animationFrameScheduler))
      .subscribe(() => {
        fifth++;
      });
    
    scheduled(interval(0), animationFrameScheduler).subscribe(() => {
      sixth++;
    });
    
    REAL:  181
    FIRST:  109
    SECOND:  217
    THIRD:  108
    FOURTH:  217
    FIFTH:  180