Angular RxJS 6页面未激活时可观察到的暂停或缓冲区

Angular RxJS 6页面未激活时可观察到的暂停或缓冲区,angular,typescript,asynchronous,rxjs,rxjs6,Angular,Typescript,Asynchronous,Rxjs,Rxjs6,所以我有一个字母流,让我们说字母,我需要所有字母按正确的顺序组合成一个单词。一切正常,直到用户更改选项卡、最小化浏览器或切换应用程序-行为几乎与我使用的setTimeout()-打乱订单、丢失物品等相同。我试图通过使用bufferWhen()、bufferToggle()、takeUntil()、publish()来实现我的目标和connect()但没有成功。我也考虑过使用delayWhen,但它已被弃用,可能不适合,因为它会立即停止流。我应该使用哪些功能以及如何使用?这是我的密码: 导出类My

所以我有一个字母流,让我们说字母,我需要所有字母按正确的顺序组合成一个单词。一切正常,直到用户更改选项卡、最小化浏览器或切换应用程序-行为几乎与我使用的
setTimeout()
-打乱订单、丢失物品等相同。我试图通过使用
bufferWhen()
bufferToggle()
takeUntil()
publish()来实现我的目标
connect()
但没有成功。我也考虑过使用
delayWhen
,但它已被弃用,可能不适合,因为它会立即停止流。我应该使用哪些功能以及如何使用?这是我的密码:

导出类MyComponent实现AfterViewInit{
私有visibilityChange$=fromEvent(文档'visibilityChange').pipe(startWith('visible')、shareReplay({refCount:true,bufferSize:1}));
private show$=this.visibilityChange$.pipe(过滤器(()=>document.visibilityState==='visible');
private hide$=this.visibilityChange$.pipe(过滤器(()=>document.visibilityState==='hidden');
公共ngAfterViewInit(){
const lettersStream$=zip(//为每个字母添加延迟
from(['w','o','r','d']),
间隔(1000)
//隐藏$fires时暂停,显示时恢复$
.pipe(映射([字母,延迟时间]=>字母))
.subscribe(console.log);
}
}

我在上做了一个演示-我只想看到(当选项卡处于非活动状态时停止写入)该短语是如何在屏幕上写入的。

对用例有点困惑,但这可能会解决它:

首先,请执行以下操作:

private isVisible$ = this.visibilityChange$.pipe(
                       filter(() => document.visibilityState === 'visible'), 
                       distinctUntilChanged()); // just a safety operator
然后这样做:

const lettersStream$ = this.isVisible$.pipe(
        switchMap((isVisible) => (isVisible)
          ? zip( // add delay for each letter
              from(['w', 'o', 'r', 'd']),
              interval(1000))
            .pipe(map(([letter, delayTime]) => letter))
          : NEVER
        )
      ).subscribe(console.log);
只要在每次可见性改变时切换地图,如果可见,订阅源代码,如果不可见,什么也不做


在这个人为设计的示例中,行为会有点不稳定,因为from()将始终发出相同的序列,但对于真正的非静态源,它应该可以正常工作。

因为我在我的示例中也做过类似的暂停/取消暂停操作,所以我将帮助您完成示例

这个想法是要有一个
间隔(1000)
作为真理的来源,这意味着一切都将以它为基础。因此,我们的目标是使此间隔可暂停,因为我们需要停止在可见性隐藏时发出事件,并在可见性显示时继续。最后,为了让事情变得更简单,我们可以停止收听visibility hide上的源间隔,并在visibility show到来时再次开始收听。现在让我们来看一下具体的实现:

您也可以在上玩修改后的StackBlitz演示代码

这正是StackBlitz的代码,我复制到这里是为了更好地为您解释

现在,让我们为您细分有趣的部分:

  • 查看
    visibilityChange$
    isvisibility$
    。它们被稍加修改,以便第一个基于
    document.visibilityState
    发出字符串值
    'visible'
    'hidden'
    。当
    document.visibilityState
    等于
    “visible”时,第二个将发出true

  • 请查看
    源代码$
    。它将发出一个字母,然后借助
    concatMap
    interval
    take(1)
    等待1秒,然后执行此过程,直到文本中没有字符为止

  • 查看一下
    pausableInterval$
    。基于此.isVisible$
    将根据
    文档.visibilityState
    进行更改,我们的
    pausableInterval$
    将每秒发射项目,或者由于
    从不()
    而根本不会发射任何东西

  • 最后看一下
    lettersStream$
    。借助于
    zip()
    ,我们将压缩
    pausableInterval$
    source$
    ,因此我们将从source获得一个字母,从pausableInterval获得一个勾号。如果
    pausableInterval$
    由于visibilitychange而停止发送,zip也将等待,因为它需要两个可观察对象一起发送事件到subscribe


  • 像这样的?嗯,不是。这些字母是一个可观测值发出的连续值,您将它们设置为的的。我在下一封信后1秒钟收到“w”,除了因更改浏览器选项卡而导致的中断之外,我还需要保持顺序。我看不到您如何在
    信流$
    中使用
    show$
    hide$
    可观察对象。我只能看到一条关于他们的评论。我是不是遗漏了什么?真正的来源是什么?是不是当标签改变时会断开连接的某种websocket?或者是文档事件还是什么?我不明白是什么导致了这个问题,或者为什么当可见性改变时你需要暂停这个流。源就像示例中的源一样,可观察的发射值,它没有断开连接,只是浏览器优先于可见选项卡,所以可以在“r”之前处理“d”项.我正在创建一个演示,并在此处使用了您的代码:
    word或Twoww…
    已打印,并且正在继续…这是由于作为源的
    。每次订阅发生时,它都会重新提交整个流。但暂停的作用正如预期的那样。它会取消订阅,并在每次可见性更改时重新订阅。好的,那么如何使用来自
    呢?你不能。您需要编写某种可以暂停的源代码,但无法使用from作为源代码来停止并在中途恢复排放。from对于osbervables在野外的行为通常不太现实,主要用于演示,在实践中很少有模糊的用例。现在还不清楚你到底想要什么。
    
    import { of, interval, fromEvent, timer, from, zip, never } from 'rxjs';
    import { delayWhen, tap, withLatestFrom, concatMap, take, startWith, distinctUntilChanged, switchMap, shareReplay, filter, map, finalize } from 'rxjs/operators';
    
    console.log('-------------------------------------- STARTING ----------------------------')
    
    class MyComponent {
      private visibilityChange$ = fromEvent(document, 'visibilitychange')
        .pipe(
          map(x => document.visibilityState),
          startWith('visible'),
          shareReplay(1)
        );
    
      private isVisible$ = this.visibilityChange$.pipe(
        map(x => x === 'visible'),
        distinctUntilChanged(),
      );
    
      constructor() {
        const intervalTime = 1000;
        const source$ = from('word or two'.split(''));
        /** should remove these .pipe(
            concatMap(ch => interval(intervalTime).pipe(map(_ => ch), take(1)))
          );*/
    
        const pausableInterval$ = this.isVisible$.pipe(
          switchMap(visible => visible ? interval(intervalTime) : never()),
        )
    
        const lettersStream$ = zip(pausableInterval$, source$).pipe(
          map(([tick, letter]) => letter),
        ).subscribe(letter => {
          this.writeLetter(letter);
        });
      }
    
      private writeLetter(letter: string) {
        if (letter === ' ') letter = '\u00A0'; // fix for spaces
        document.body.innerText += letter;
      }
    }
    
    const component = new MyComponent();