rxjs switchMap缓存过时的结果,并且不创建新的流

时间:2019-02-12 09:25:16

标签: rxjs reactive-programming switchmap

const s1$ = of(Math.random())
const s2$ = ajax.getJSON(`https://api.github.com/users?per_page=5`)
const s3$ = from(fetch(`https://api.github.com/users?per_page=5`))
const click$ = fromEvent(document, 'click')
click$.pipe(
    switchMap(() => s1$)
).subscribe(e => {
    console.log(e)
})

我对上面的代码感到困惑,无法正确地推理它们。 在第一种情况(s1$)中,每次都收到相同的结果,即使我不明白为什么switchMap每次都不启动新的流,这对我来说也很好。好的,很好

当您运行s2$s3$时,看起来确实很有趣,对吗?错误!!!如果您尝试一下,行为将完全不同!

s3$的结果以某种方式被缓存,即,如果您打开网络面板,您将看到http请求仅发送一次。相比之下,每次为s2$

发送http请求

我的问题是我无法直接使用ajax中的rx之类的东西,因为http请求被隐藏了第三方库,我能想到的解决方案是使用内联流,即每次都创建新的流

click$.pipe(
    switchMap(() => from(fetch(`https://api.github.com/users?per_page=5`)))
).subscribe(e => {
    console.log(e)
})

那么,我如何能准确解释这种行为?解决这种情况的正确方法是什么?

1 个答案:

答案 0 :(得分:2)

一个问题是您在设置测试用例时实际上执行了<View style={{width:100,height:0,borderBottomWidth:100,borderBottomColor:'#000',borderLeftWidth:0,borderRightWidth:50,borderRightColor:'#000'}}> </View> Math.random

fetch

另一个是// calling Math.random() => using the return value const s1$ = of(Math.random()) // calling fetch => using the return value (a promise) const s3$ = from(fetch(`https://api.github.com/users?per_page=5`)) 返回一个承诺,该承诺只能解决一次。 fetch然后不需要重新执行ajax调用,它只会发出已解析的值。

from(<promise>)返回的流每次都会重新执行。

如果用ajax.getJSON包装测试流,则会得到更直观的行为。

defer
const { of, defer, fromEvent } = rxjs;
const { ajax }                 = rxjs.ajax;
const { switchMap }            = rxjs.operators;

// defer Math.random()
const s1$ = defer(() => of(Math.random()));

// no defer needed here (already a stream)
const s2$ = ajax.getJSON('https://api.github.com/users?per_page=5');

// defer `fetch`, but `from` is not needed, as a promise is sufficient
const s3$ = defer(() => fetch('https://api.github.com/users?per_page=5'));

const t1$ = fromEvent(document.getElementById('s1'), 'click').pipe(switchMap(() => s1$));
const t2$ = fromEvent(document.getElementById('s2'), 'click').pipe(switchMap(() => s2$));
const t3$ = fromEvent(document.getElementById('s3'), 'click').pipe(switchMap(() => s3$));

t1$.subscribe(console.log);
t2$.subscribe(console.log);
t3$.subscribe(console.log);