简体   繁体   English

如何在 RXJS retryWhen 中发出/合并另一个 observable

[英]How to emit/merge another observable inside RXJS retryWhen

I have an observable for api request, basically I added retryWhen in the event connection failed/error.我有一个 api 请求的 observable,基本上我在连接失败/错误的事件中添加了retryWhen While doing so I want to dispatch another action (no notify the user the system is retrying..) when the request is throwing an error.这样做时,我想在请求抛出错误时调度另一个操作(不通知用户系统正在重试..)。

//....
export const saveArticle1 = (action$, state$) =>
  action$.pipe(
    ofType(AUTO_SAVE_ARTICLE_READY),
    withLatestFrom(state$, (a, b) => b),
    switchMap(({
      article,
    }) => {
      const payload = getArticlePayload(article);
      return ajax.patch(`/api/article/${article.id}`, payload, { 'Content-Type': 'application/json' }).pipe(
        flatMap(({ response }) => of({
          type: ARTICLE_AUTO_SAVED,
          value: response,
        })),
        retryWhen(errors =>
          errors.pipe(
            // TODO: I try to concat or merge observable here but no luck
            delay(1000),
            take(60),
          ),
        ),
        catchError((ex) => {
          articleSaveFailureAlert();
          return showErrorNotification('Api Error. Unable to save this article.')(ex);
        }),
      );
    }),
  );

What is the best way to dispatch another action inside retryWhen ?retryWhen调度另一个动作的最佳方法是什么? or is there another way to achieve this?还是有另一种方法来实现这一目标?

You can use a recursive loop with the stopping condition that the number of attempts made is greater than the maximum allowed attempts.您可以使用递归循环,其停止条件是尝试次数大于允许的最大尝试次数。 Then you can concatenate a single observable of your "retry" action with the patch observable.然后,您可以将“重试”操作的单个 observable 与补丁 observable 连接起来。 If you edit the snippet to change maxAttempts to a number lower than 5 you'll see the "failure" action being emitted.如果您编辑代码段以将maxAttempts更改为小于 5 的数字,您将看到正在发出“失败”操作。

As an aside - you might want to double-check your use of switchMap when triggering an API call that makes a persistent change. switchMap在触发进行持久更改的 API 调用时,您可能需要仔细检查您对switchMap的使用。 Here's an article that explains the issue in detail.这里有一篇文章详细解释了这个问题。

 const {of, operators, throwError, timer, concat} = rxjs; const {switchMap, catchError, flatMap} = operators; const maxAttempts = 60; const patch = (article, attempt) => { if (attempt < 5) return throwError(new Error('server unavailable')); return of(article); }; const action$ = of('patch.id'); const saveArticle1 = action$.pipe( switchMap((article) => { const loop = (attempt) => { return patch(article, attempt).pipe( flatMap((response) => of({ type: 'saved', value: response, })), catchError(error => { if (attempt > maxAttempts) return of({ type: 'failed' }); return timer(1000).pipe( switchMap(() => concat( of({ type: 'retrying' }), loop(attempt + 1) ) ) ); }) ); }; return loop(0); }), ); saveArticle1.subscribe({ next: x => console.log('next', x), error: e => console.error(e), complete: () => console.log('complete') });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/6.5.4/rxjs.umd.js"></script>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM