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

Я обновляю множество записей в @ 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 или другой способ решить эту проблему?


person ed4becky    schedule 11.11.2020    source источник


Ответы (2)


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

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

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

this.updateEntities().subscribe();

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

PS: имейте в виду, что когда вы вызываете toPromise () для Observable, он будет выполнен немедленно.

person Marco Nascimento    schedule 23.11.2020

Опция 1

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

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

ПРИМЕЧАНИЕ. Мы возвращаем Observable, поэтому там, где вы изначально вызвали это Promise, нужно будет изменить с .then() на 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
      });

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

person Owen Kelvin    schedule 17.11.2020