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();