Angular 在自动保存场景中,以何种顺序使用哪些rxjs运算符

Angular 在自动保存场景中,以何种顺序使用哪些rxjs运算符,angular,rxjs,Angular,Rxjs,我想用RxJS在Angular中自动保存一个表单。 表单更改时将发出一个事件 这是一个场景: 当表单输出已更改,但在接下来的10秒内不再更改时,它应发出一个保存事件 只有当窗体每10秒更改一次以上(至少30秒)时,它才应发出保存事件 对于第一个,我可以使用去盎司,但如何将其与第二个规则结合起来?您需要将流分成两个流 const source=fromEvent(document.getElementById(“text”),“input”); 来源 .管道(去BounceTime(10*1000

我想用RxJS在Angular中自动保存一个表单。 表单更改时将发出一个事件

这是一个场景:

  • 当表单输出已更改,但在接下来的10秒内不再更改时,它应发出一个保存事件

  • 只有当窗体每10秒更改一次以上(至少30秒)时,它才应发出保存事件


  • 对于第一个,我可以使用去盎司,但如何将其与第二个规则结合起来?

    您需要将流分成两个流

    const source=fromEvent(document.getElementById(“text”),“input”);
    来源
    .管道(去BounceTime(10*1000))
    .subscribe(()=>console.log(“键入后保存”);
    来源
    .烟斗(
    审核时间(10*1000)
    )
    .subscribe(()=>console.log(“键入时保存”);
    
    在第一种情况下,如您所述,使用debounceTime值将在用户完成编辑表单/输入10秒后发出。在第二种情况下,auditTime每10秒将检查是否有任何新值。如果有,则会发出值。在回调中,您可以重用负责从表单保存数据的相同函数。 您可以在stackblitz的演示中尝试:

    我只是将演示中的时间改为1秒,这样在控制台中更容易检查结果

    旁注:

    这是简单的JS演示。如果开发Angular应用程序,应该避免使用getElementById获取元素。不要使用直接引用模板:

    编辑:

    根据OP评论,我对实现做了一点修改。我合并了两个观察值,并使用distinctUntilChanged操作符避免两次发出相同的值。stackblitz中的演示也发生了变化

    const-postertyping=source.pipe(debounceTime(1000));
    const whileTyping=source.pipe(审核时间(1000));
    合并(同时键入,后键入)
    .pipe(distinctUntilChanged())
    .subscribe(console.log);
    
    这个问题有点棘手,但是将
    去BounceTime
    节流时间
    适当组合可以解决问题:

    const s = new Subject();
    s.subscribe();
    
    const saveEvery3sSubject = new Subject();
    saveEvery3sSubject.subscribe();
    
    const saveEvery3s$ = saveEvery3sSubject.pipe(
      throttleTime(3000),
      mapTo('saving after 3000 ms'),
      startWith(null)
    );
    
    
    const debounce$ = s.pipe(
      tap(r => {
        saveEvery3sSubject.next(r); // this step starts the 3000ms timer
      }),
      debounceTime(1000),
      startWith(null),
    );
    
    // combining them both so the saving will occur on debounce or after 3000ms
    const result$ = combineLatest([debounce$, saveEvery3s$]).pipe(
        filter(([d, s]) => s !== null)
    )
    
    
    // first 5 values will be debounced forever because 500 < 1000(debounceTime)
    interval(500).pipe(
        take(5)
    )
      .subscribe(i => {
        s.next('form changed #' + i);
    })
    
    // these values will be emitted correctly one by one
    timer(9000, 1100).pipe(
        take(20)
    )
      .subscribe(i => {
        s.next('after pause #' + i);
    })
    
    result$.subscribe();
    
    const s=新主题();
    s、 订阅();
    const saveevery3subject=新主题();
    SaveEvery3Subject.subscribe();
    const saveEvery3s$=saveEvery3sSubject.pipe(
    节流时间(3000),
    映射到(“3000毫秒后保存”),
    startWith(空)
    );
    const debounce$=s.pipe(
    点击(r=>{
    saveEvery3sSubject.next(r);//此步骤启动3000ms计时器
    }),
    去BounceTime(1000),
    startWith(空),
    );
    //将两者结合在一起,以便在去盎司时或3000毫秒后进行保存
    const result$=CombineTest([debounce$,saveEvery3s$])。管道(
    过滤器(([d,s])=>s!==null)
    )
    //前5个值将永远去噪,因为500<1000(去噪时间)
    间隔(500)。管道(
    采取(5)
    )
    .订阅(i=>{
    s、 下一步(‘形式改变#’+i);
    })
    //这些值将一个接一个地正确发出
    计时器(9000、1100)。管道(
    采取(20)
    )
    .订阅(i=>{
    s、 next(‘暂停后#’+i);
    })
    结果$.subscribe();
    
    使用附加主题是必要的,因为您操作两个独立的时间框架:

    • debounceTime-更改表单并发出更改时
    • throttleTime-确保表单每30秒保存一次,而不考虑取消公告的输入(如果您比取消公告的时间快,那么这些值根本不会发出!)
    在第一次formChange使用debounce输入流之后,它启动计时器(在我的示例中为-3000ms),这意味着如果没有用户输入,就不会有必要的排放

    还要注意
    startWith(null)
    -这是
    combinelatetest
    发出第一个值所必需的

    这一解决方案正在发挥作用:

    您能更清楚地解释第二个指针吗?您能分享您已经尝试过的代码以及您遇到的问题吗?谢谢,有一个问题:如果我加载stackblitz并键入一个字符,它将保存两次,一次来自源代码1,另一次来自源代码2。最理想的是一个。我想我需要清除audittime事件,无论何时解盎司时间发出?我能做到吗?当然有可能。我在answer和StackBlitzThank中更改了实现,并对其进行了测试,这正是我所需要的,清晰而简单