【问题标题】:RxJS throttle for AJAX requestsAJAX 请求的 RxJS 限制
【发布时间】:2019-05-23 19:32:08
【问题描述】:

我想创建一个向后端发出 AJAX 请求的函数。如果这个函数同时被多次调用,那么它不应该向服务器发出许多相同的请求。它只能发出 1 个请求。

例如:

doAJAX('http://example-1.com/').subscribe(res => console.log); // must send a request
doAJAX('http://example-1.com/').subscribe(res => console.log); // must NOT send a request
doAJAX('http://example-2.com/').subscribe(res => console.log); // must send a request, bacause of different URL
window.setTimeout(() => {
    doAJAX('http://example-2.com/').subscribe(res => console.log); // must send a request because too much time has passed since the last request
}, 3000)

所有的函数调用都应该返回一个结果,就好像请求是真的发出的一样。

我认为为此我可以使用 RxJS 库。 我已经这样做了:

const request$ = new Subject < string > ();

const response$ = request.pipe(
    groupBy((url: string) => url),
    flatMap(group => group.pipe(auditTime(500))), // make a request no more than once every 500 msec
    map((url: string) => [
        url,
        from(fetch(url))
    ]),
    share()
);

const doAJAX = (url: string): Observable <any> {
    return new Observable(observe => {
        response$
            .pipe(
                filter(result => result[0] === url),
                first(),
                flatMap(result => result[1])
            )
            .subscribe(
                (response: any) => {
                    observe.next(response);
                    observe.complete();
                },
                err => {
                    observe.error(err);
                }
            );
        request$.next(url);
    });
}

我创建 request$ 主题和 response$ 可观察的。 doAjax 函数订阅 response$ 并将 URL 字符串发送到 request$ 主题。 request$ 流中还有 groupByauditTime 运算符。并在doAJAX 函数中过滤运算符。

此代码有效,但我认为它非常困难。有没有办法让这个任务更容易?也许是 RxJS 调度器或者根本不使用 RxJS 库

【问题讨论】:

    标签: rxjs


    【解决方案1】:

    由于这样做的重点是记忆 Http 结果并延迟重复调用,您可以考虑自己的记忆。示例:

    const memoise = (func) => {
      let cache: { [key:string]: Observable<any> } = {};
    
      return (...args): Observable<any> => {
        const cacheKey = JSON.stringify(args)
        cache[cacheKey] = cache[cacheKey] || func(...args).pipe(share());
    
        return cache[cacheKey].pipe(
          tap(() => timer(1000).subscribe(() => delete cache[cacheKey]))
        );
      }
    }
    

    这是Stackblitz DEMO

    【讨论】:

    • 非常感谢。它真的帮助了我。一个小修复,在您的示例中永远不会调用 delete cache[cacheKey] (我不知道为什么您的示例中的 memoize 有效,也许是 stackblitz 中的服务人员)这里是固定演示:stackblitz.com/edit/nhrtsp-cvzxsz?file=index.ts
    • 是的,有这样的问题。因为tap(() =&gt; timer(1000).pipe( 只是创建了新的 Observable 新函数。并且subscribing 像你一样可以 - timer(1000) 自行完成,因此不需要取消订阅,如果没有更深层次的逻辑,我同意在这里订阅是可以的(与将timer() 合并到主流相比,通常是首选方式)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 2011-10-21
    • 2011-09-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多