【问题标题】:ZipWithLatestForm *Wanted Operator* or WorkaroundZipWithLatestForm *Wanted Operator* 或解决方法
【发布时间】:2019-04-23 08:33:26
【问题描述】:

让我们考虑以下流:

Stream1: 1  2  3  4  5  6  7  8  9                
Stream2: abc  d       fg   h

我想通过组合这些流来获得输出:

[1, a]
[2, b]
[3, c]
[4, d]
[5, d]
[6, f]
[7, g]
[8, h]
[9, h]

示例代码创意: StackBlitz Editor Link

const input$ = fromEvent(document, 'keydown')
  .pipe(
    map((event: KeyboardEvent) => event.keyCode)
  );
const source$ = interval(500).pipe(s$ => zip(s$, input$))
source$.subscribe(x => console.log(x));

所以这类似于运营商zip() 和/或withLatestForm(),但我想不出解决方案

  • 主要想法是我有 500 毫秒的间隔,并且在每个滴答声上,我都想用 Keyboard Input Observable 压缩它,这可以按我的意愿工作,但只要我不发出 Keyboard Input Observable 一切都会停止。 我想继续发出间隔滴答声,但如果键盘事件停止,则采用最新值

【问题讨论】:

  • 您问题开头的输出是否真的代表了您的用例?我完全不确定它确实如此。在这种情况下,您的问题中有两个问题。
  • 我想我没有给出最好的描述。是的,它确实代表了我的情况。每当键盘输入的输入速度快于间隔滴答声时,我希望它们在某种程度上保存在内存中,以便在以后的滴答声到达时将它们匹配在一起,但是每当没有更多键盘输入时,我希望最新的键盘输入与滴答声匹配跨度>
  • 请再次查看流,我编辑它们以更好地展示我的用例
  • 我假设您希望有一个间隔来继续并从您输入的内容(键盘事件)中获取最新值。请看下面是您的 Stackblitz 的分支,我对其进行了修改以尝试回答您的问题。
  • 我的帖子因信息不全,没有解决问题,被版主删除。但是,如果您仍然感兴趣 - here 是链接。修改最少,你需要的运算符是combineLatest

标签: javascript typescript rxjs reactive-programming rxjs6


【解决方案1】:

你可以只使用 withLatestFrom

import { of, fromEvent, interval } from 'rxjs'; 
import { map, withLatestFrom } from 'rxjs/operators';

const input$ = fromEvent(document, 'keydown').pipe( map((event: KeyboardEvent) => event.keyCode));
const timer$ = interval(1000);
const source$ = timer$.pipe(withLatestFrom(input$));

source$.subscribe(x => console.log(x));

在 stackblitz 上试试这个现场演示 -> https://stackblitz.com/edit/rxjs-bmx7hg

只要您聚焦页面并按下某个键,流就会启动,并且您将在每次滴答时获得一个发出的值,无论您是否在上次滴答后点击了按钮。

【讨论】:

  • 请再次查看流,我编辑它们以更好地展示我的用例。至于我的用例,请考虑我希望拥有更多类似 zip 的功能,因为使用 withLatestFrom() 将在任何(source1 或 source2)可观察对象发出时发出。而且我会在最终订阅时获得比我想要的更多的发射项目
  • 不,通过使用 withLatestFrom,它只会在源流(在我的示例中为 timer$)发出时发出。您也可以在我的演示中检查这一点 - 只需疯狂地按下键盘按钮 - 每秒只会发出一个值
  • 是的,我同意你的观点,但使用 withLatesForm() 会给我 [1, a] 和 [2, c]。 [2,b] 将被跳过。
【解决方案2】:

我不太了解 rxjs,无法说出是否有内置函数可以做到这一点,但您应该能够使用显式队列来处理它:

import { of, fromEvent, interval } from 'rxjs'; 
import { map, withLatestFrom } from 'rxjs/operators';

const queue = [];
const input$ = fromEvent(document, 'keydown').pipe(map((event: KeyboardEvent) => {
    queue.push(event.keyCode);
    return queue;
});
const timer$ = interval(1000);
const source$ = timer$.pipe(withLatestFrom(input$), map(([tick, queue]) => {
    if (queue.length > 1)
        return queue.shift();
    else
        return queue[0];
}));

source$.subscribe(console.log);

【讨论】:

  • 谢谢,我想这会起作用,因为我的案例正是队列功能。我想要某种 rxjs 运算符
【解决方案3】:

经过一段时间的思考,我想出了这样的解决方案,StackBlitz Edit Link:

const interval$ = interval(500).pipe(share());
const input$ = fromEvent(document, 'keydown')
  .pipe(
    map((event: KeyboardEvent) => event.keyCode),
    concatMap(key => interval$.pipe(map(tick => key), take(1))),
  );

const source$ = interval$.pipe(withLatestFrom(input$))
source$.subscribe(x => console.log(x));

我在 interval$ 和 concatMap 的帮助下延迟了 input$(也请注意 take(1))。

ConcatMap 帮助我延长 input$ 事件并等待间隔事件触发自己的事件。使用 withLatestForm 帮助我将刻度与它们自己的 input$ 值匹配。

【讨论】:

    猜你喜欢
    • 2020-09-12
    • 2021-10-22
    • 1970-01-01
    • 2012-08-16
    • 2011-12-09
    • 2012-11-08
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多