首页 > 解决方案 > 如何使用 2 个 observable 发出的值作为 http 请求的参数,其中 1 个 observable 将另一个设置为默认值?

问题描述

我正在订阅基于其他 2 个可观察对象的映射可观察对象。每当 2 中的任何一个发出一个值时,我都希望映射的 observable 发出。

每当外部可观察值发出时,内部可观察值应重置为默认值(示例中为 0)。问题是当我重置内部值时,会发出一个额外的值。

(对于上下文 - 2 个 observable 为 http 请求提供参数,这是映射的 observable。新的外部值应将内部值重置为 0)

const outer = new Subject();
const inner = new BehaviorSubject(0);
const http = of("");
let mapped = outer.pipe(
  tap(() => inner.next(0)),
  switchMap(outerVal => {
    return inner.pipe(map(innerVal => ({ innerVal, outerVal })));
  }),
  switchMap(({ innerVal, outerVal }) => {
    return http.pipe(tap(() => console.log("http: ", outerVal, innerVal)));
  })
);

mapped.subscribe(result => {
  console.log(result);
});

outer.next("first");
inner.next(1);
inner.next(2);
outer.next("second");
inner.next(3);


// http: first 0
// http: first 1
// http: first 2
// http: first 0 <--- extra
// http: second 0
// http: second 3

我知道它为什么会发生,但我不知道如何处理它。我有一个解决方案可以在这个 stackblitz 的底部得到正确的结果,但我认为它会导致内存泄漏。

https://stackblitz.com/edit/rxjs-mxc5wq?file=index.ts

标签: javascriptangulartypescriptrxjs

解决方案


以下具有您想要的输出。我不确定它是否符合您的标准。你的内在可观察物必须是行为主体,有什么理由吗?如果只是给它一个初始值,那么startWith操作员会做得更干净。

const outer = new Subject();
const inner = new Subject();
const http = of("");

const mapped = outer.pipe(
  switchMap(outerVal =>
    inner.pipe(
      startWith(0),
      map(innerVal => ({ innerVal, outerVal }))
    )
  ),
  switchMap(({ innerVal, outerVal }) => 
    http.pipe(
      tap(() => console.log("http: ", outerVal, innerVal))
    )
  )
);

mapped.subscribe(console.log); // ""

你的 stackblitz 内存泄漏

您正在创建长期存在的多播流并且从未完成它们。你可以试试:

tap(() => {
  inner2.complete();
  inner2 = new BehaviorSubject(0);
}),

SwitchMap 将取消订阅,但多播流不会在取消订阅时完成(取决于它的refcount工作方式)。


推荐阅读