Как избежать net ::ERR_INSUFFICIENT_RESOURCES, когда ngrx / data выполняет удаленные вызовы api?

#angular #angular-ngrx-data #ngrx-data

#angular #angular-ngrx-data #ngrx-data

Вопрос:

Я обновляю множество записей в разделе @ngrx /data, который вызывает удаленный API в фоновом режиме для синхронизации базы данных и локального хранилища.

   dataList.forEach((entity) => {
    const p = this.entitySvc
      .getEntityCollectionService(storeName)
      .upsert(entity)
      .toPromise();
    promises.push(p);
  });
  return Promise.all(promises);
  

Проблема, с которой я сталкиваюсь, заключается в том, что удаленный вызов API происходит за пределами моего кода, и это происходит так быстро, что соединения перегружают браузер:

net::ERR_INSUFFICIENT_RESOURCES

Регулирование приведенного выше кода не помогает, потому что удаленные вызовы API происходят вне моего контроля.

Есть ли способ ограничить вызовы удаленного API ngrx / data или другой способ решения этой проблемы?

Ответ №1:

Я бы использовал оператор mergeMap rxjs, чтобы добавить параллелизм между запросами сервера:

 updateEntities(): Observable<any> {
  return from(dataList).pipe(
    mergeMap(entity => this.entitySvc
     .getEntityCollectionService(storeName)
     .upsert(entity), 2)
  );
}
  

Затем при необходимости вызывайте функцию:

 this.updateEntities().subscribe();
  

Обратите внимание, что значение параллельного параметра mergeMap равно 2, что означает, что параллельно будут отправляться только 2 запроса, предотвращая одновременное обращение к серверу одновременно. Вы можете настроить это число по своему усмотрению.

PS: Имейте в виду, что при вызове функции toPromise() для наблюдаемого объекта она будет выполнена немедленно.

Ответ №2:

Вариант 1

Приведенный ниже подход с использованием Observable без необходимости сначала конвертировать в promise должен снизить использование ресурсов, попробуйте

   import { forkJoin } from 'rxjs'
  ...
  myFunction() {
     return forkJoin(dataList.map(entity => this.entitySvc
      .getEntityCollectionService(storeName)
      .upsert(entity)))
  }
 

  

ПРИМЕЧАНИЕ: мы возвращаем an Observable , поэтому там, где вы изначально вызывали это Promise , нужно будет изменить с a .then() на a subscribe()

 myFunction().subscribe()
  

Вариант 2

Если вышеуказанное не решает, попробуйте ниже. Подход связывает Observable и обрабатывает следующий запрос только после завершения предыдущего запроса.

ПРИМЕЧАНИЕ: это может быть медленнее, и вам может потребоваться указать пользователю ход выполнения операции

     this.dataList
      .pipe(
        tap(() => 0),
        tap(({ length }) => (this.totalItems = length)),
        flatMap(item => item)
      )
      .pipe(
        concatMap(entity =>
          this.entitySvc.getEntityCollectionService(storeName).upsert(entity)
        )
      )
      .pipe(tap(() => (this.progress  = 1)))
      .subscribe({
        next: console.log
      });
  

Посмотрите эту демонстрацию