【问题标题】:Debounce and buffer an rxjs subscription去抖和缓冲一个 rxjs 订阅
【发布时间】:2018-05-24 17:49:41
【问题描述】:

我有一个消息队列处理器,可以将消息提供给服务...

q.on("message", (m) => {
  service.create(m)
    .then(() => m.ack())
    .catch(() => n.nack())
})

该服务使用 RxJS Observable 并订阅 debounceTime() 这些请求。

class Service {
  constructor() {
    this.subject = new Subject()
    this.subject.debounceTime(1000)
      .subscribe(({ req, resolve, reject }) =>
        someOtherService.doWork(req)
          .then(() => resolve())
          .catch(() => reject())
      )
  }

  create(req) {
    return new Promise((resolve, reject) =>
      this.subject.next({
        req,
        resolve,
        reject
      })
    )
  }
}

问题是只有去抖动的请求才会被确认/取消。如何确保订阅也解决/拒绝其他请求? bufferTime() 让我参与其中,但它不会重置每次调用 next() 的超时持续时间。

【问题讨论】:

  • 您可以将buffer 与从debounceTime 构建的关闭通知一起使用。有关基本机制,请参阅this answer。这将在谴责期限内为您提供所有排放量,您可以随心所欲地处理它们。
  • 由于该解决方案合并了两个流,您将如何在此处合并该方法?
  • 您可以将合并排除在外。通知缓冲区很常见——通知程序使用debounceTime 而不是auditTime。我可以尽快给你写一个答案;之前在移动设备上。
  • 我明白你现在的意思了......尝试了这种方法,似乎有效。

标签: rxjs rxjs5


【解决方案1】:

对于那些正在寻找 RXJS 6 解决方案的人,我创建了一个自定义运算符,其行为类似于上一个答案中的 debounce() + buffer()

我称它为 bufferDebounce,Typescript 中带有类型推断的 sn-p 在这里:

import { Observable, OperatorFunction } from 'rxjs'
import { buffer, debounceTime } from 'rxjs/operators'

type BufferDebounce = <T>(debounce: number) => OperatorFunction<T, T[]>;
const bufferDebounce: BufferDebounce = debounce => source =>
  new Observable(observer =>
    source.pipe(buffer(source.pipe(debounceTime(debounce)))).subscribe({
      next(x) {
        observer.next(x);
      },
      error(err) {
        observer.error(err);
      },
      complete() {
        observer.complete();
      },
    }),
  );

您可以在此示例中测试其行为以检查这是否适合您https://stackblitz.com/edit/rxjs6-buffer-debounce

【讨论】:

    【解决方案2】:

    您当前使用的debounceTime 运算符可用于创建一个可通知buffer 当前缓冲区应何时关闭的可观察对象。

    然后,buffer 将发出一个在去抖动时收到的消息数组,您可以随心所欲地处理它们:

    this.subject = new Subject();
    const closingNotifier = this.subject.debounceTime(1000);
    this.subject.buffer(closingNotifier).subscribe(messages => {
      const last = messages.length - 1;
      messages.forEach(({ req, resolve, reject }, index) => {
        if (index === last) {
          /* whatever you are doing, now, with the debounced message */
        } else {
          /* whatever you need to do with the ignored messages */
        }
      });
    });
    

    【讨论】:

    • 那么为什么没有bufferDebounce 运算符呢?我犯了buffer(100) 的错误,我只是偶然发现我永远每100ms 得到一个空数组!我原以为buffer(100) 如果为空,则不会发出任何内容。如果 10 秒内没有任何消息,我假设此版本不会运行回调。
    • 我想这是因为其他人会要求bufferAuditbufferThrottle 等,其中任何一个都可以由buffer 和通知程序构建。
    • 我很高兴我发现buffer(0) 在为时已晚或令人困惑之前不是一个好主意!有点像使用shareReplay() 当你真的想把shareReplay(1) ;-)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-22
    • 1970-01-01
    相关资源
    最近更新 更多