【问题标题】:How to smooth stream Rxjs?如何平滑流 Rxjs?
【发布时间】:2020-10-12 22:22:47
【问题描述】:

我有一个 Rxjs:

   private loading = new BehaviorSubject(false);

loading 可以从true 快速更改为false。仅当 falsetrue 之间的时间超过 3 秒时,如何平滑此流并传递值,否则默认传递 false?

【问题讨论】:

  • 只有当falsetrue 之间的时间超过3 秒时,您才想发出true,否则发出false

标签: rxjs rxjs5


【解决方案1】:

您好 Megan,您可以查看以下演示,我认为它可以帮助您解决您面临的问题。 (我使用的是 1500 毫秒而不是 3000 毫秒,但没那么重要)

因此,问题的第一部分是您希望能够以特定时间间隔获取有关加载状态的过去状态(存储在BehavourSubject 中的值)的信息。

这是通过buffer 运算符和interval observable 的组合来实现的。这个想法是buffer 将记录通过流发出的所有事件,并在作为参数传递的 observable 发出一个值时传递它们(在我们的例子中,interval observable 将每 1500 毫秒发出一个新值)

所以每 1500 毫秒我们都会从加载主题中获得新的值。

接下来我们需要处理的是确保主题在过去 1500 毫秒内保持不变,我实现这一点的方法是使用 scan 运算符来存储主题最后发出的值。

使用后续filter 运算符中的聚合数据,我正在检查主题中是否写入了任何新值(如果有的话,它们可以通过newEvents 变量访问,这将是最后缓冲的主题值的数组)

因此过滤条件几乎表明如果过去 1500 毫秒内没有事件,则应传递最新的加载值。

在管道的末尾distinctUntilChanged 用于过滤掉任何重复的加载状态,因此只有在出现新的加载/加载状态时,才会更改 HTML 中的值。

let {
  BehaviorSubject,
  interval
} = rxjs
let {
  buffer,
  scan,
  map,
  filter,
  distinctUntilChanged
} = rxjs.operators

let someFlagToSaveTheCurrentState = false;
let currentState = document.getElementById('currentState')

let loading = document.getElementById('loading')
let loadingBtn = document.getElementById('loadingbtn')

let loader = new BehaviorSubject(false)

loadingBtn.addEventListener('click', () => {
  someFlagToSaveTheCurrentState = !someFlagToSaveTheCurrentState;
  loader.next(someFlagToSaveTheCurrentState);

  currentState.innerHTML = someFlagToSaveTheCurrentState;
})

let interval$ = interval(1500)

loader.pipe(
  buffer(interval$),
  scan((acc,e) => ([...acc.slice(1),e]), [[false], [false]]),
  filter(([lastEvents, newEvents]) => newEvents.length === 0 && lastEvents.length !== 0),
  map(([lastEvents, newEvents]) => {
  let result = false;
  if (newEvents.length === 0 && lastEvents.length !== 0) {
    result = lastEvents[lastEvents.length - 1]
  }
  return result;
}),
distinctUntilChanged()
  
).subscribe((loadingState) => {
  console.log(loadingState)
  if (loadingState) {
    loading.innerHTML = 'Element loading'
  } else {
    loading.innerHTML = 'Element is loaded'
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.5/rxjs.umd.js"></script>

<h1 id="loading">Loading</h1>

<button id="loadingbtn">Toggle loading</button>
<h1 id="currentState">false</h1>

尝试运行代码 sn-p

【讨论】:

    【解决方案2】:

    您可以使用debounceTime() 让您的流在发出值之前等待给定的持续时间。 (https://www.learnrxjs.io/learn-rxjs/operators/filtering/debouncetime)

    要在订阅流时直接发出默认值,您必须使用startWith() (https://www.learnrxjs.io/learn-rxjs/operators/combination/startwith) 为您的(去抖动的)流添加默认值 p>

    const $loadingState = loading
      .pipe(
        debounceTime(5 * 1000),
        startWith(false)
      );
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-03-27
      • 2020-05-26
      • 2011-11-06
      • 2012-07-30
      • 2012-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多