Последовательно выполнить один внутренний вызов с повторными попытками в Angular с помощью RxJS

#javascript #angular #rxjs

#javascript #angular #rxjs

Вопрос:

У меня есть некоторый код Javascript, который удаляет документы из базы данных с помощью вызовов API. Между документами существуют внутренние зависимости, поэтому удаление может завершиться неудачей. Таким образом, код попытается удалить все документы в 5 раундах.

Но поскольку я использую Angular и использую RxJS для всех других задач, было бы неплохо использовать решение RxJS, а не async / await и promises. Мне удалось удалить один раунд с помощью concatMap, но как добиться повторных попыток на месте?

 private async deleteDocuments(documents: IDocument[]) {
    let retries = 5;
    let remaining = [...documents];
    while (remaining.length > 0 amp;amp; retries > 0) {
        remaining = await this.deleteDocumentsOneTry(remaining);
        retries--;
    }
}

private async deleteDocumentsOneTry(documents: IDocument[]) {
    const remaining: IDocument[] = [];
    for (const document of documents) {
        const deleted = await this.deleteDocument(document);
        if (deleted) {
            this.documentsDeleted  ; // For progress bar
        } else {
            remaining.push(document);
        }
    }

    return remaining;
}

private deleteDocument(document: IDocument) {
    console.log(`Delete document ${document.name}`);
    return this.backend
        .deleteDocuments(document.id)
        .pipe(
            map(() => true),
            catchError(() => of(false))
        )
        .toPromise();
}
  

Ответ №1:

Рассмотрите возможность его реализации, как показано ниже:

 return from(documents).pipe(
  mergeScan((failed: number, document: IDocument) => {
    return that.backend.deleteDocuments(document.id).pipe(
      tap(x => this.documentsDeleted  ),
      mapTo(failed),
      catchError((error, source) => failed < 5 ? source.pipe(mapTo(  failed)) : throwError(error))
    )
  }, 0)
)
  

Упрощенная реализация:

 let retries = 5;

from(documents).pipe(
  concatMap(doc => that.backend.deleteDocuments(doc.id).pipe(
    catchError((error, source) => --retries > 0 ? source : throwError(error)),
  ))
).subscribe((x) => this.documentsDeleted  )