RxJS节流阀用于AJAX请求

时间:2019-05-23 19:32:08

标签: rxjs

我想创建一个将向后端发出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$主题。 groupBy流中还有auditTimerequest$个运算符。还有doAJAX函数中的filter运算符。

此代码有效,但我认为这非常困难。有没有一种方法可以使此任务更轻松?也许RxJS调度程序或根本不使用RxJS库

1 个答案:

答案 0 :(得分: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