Дроссель RxJS для запросов AJAX - PullRequest
2 голосов
/ 23 мая 2019

Я хочу создать функцию, которая будет выполнять запросы 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$ есть операторы groupBy и auditTime. И оператор фильтра в функции doAJAX.

Этот код работает, но я думаю, что это очень сложно. Есть ли способ облегчить эту задачу? Может быть, планировщик RxJS или не использовать библиотеку RxJS вообще

1 Ответ

1 голос
/ 25 мая 2019

Поскольку весь смысл этого состоит в том, чтобы запоминать результаты 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]))
    );
  }
}

Вот DEMO * Stackblitz

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...