RxJS mergeMap 运算符内部的错误处理

Cod*_*n25 5 subscription observable rxjs angular angular-httpclient

当我使用 Angular HttpClient 发出 GET 请求时,我会得到一个可观察的数据并在 RxJS 运算符 mergeMap 中处理它。

现在,一次又一次地抛出 404,我想抓住它。最后,浏览器控制台中不应出现任何错误消息,并且应使用流的下一个值来处理管道。

有这种可能吗?我没有用catchError()来管理它。

这是我的代码的简化版本:

    ...
    this.service1.getSomeStuff().pipe(
          mergeMap((someStuff) => {
            return from(stuff);
          }),
          mergeMap((stuff) => {
            return this.service2.getMoreStuff(stuff.id); // Here I need some error handling, if 404 occurs
          }),
          mergeMap((things) => {
            return from(things).pipe(
              mergeMap((thing) => {
                if (allLocations.some(x => x.id === metaData.id)) {
                  return this.service2.getMore(thing.id, thing.type, thing.img_ref);
                }
              }),
              map((thing) => {
              ...
Run Code Online (Sandbox Code Playgroud)

更新:添加了 catchError() 方法

我尝试了这种方式,但是没有检测到错误,并且下一个 mergeMap 不起作用(IDE 不再识别thing.id、thing.type、th​​ing.img_ref等参数):

...
this.service1.getSomeStuff().pipe(
      mergeMap((someStuff) => {
        return from(stuff);
      }),
      mergeMap((stuff) => {
        return this.service2.getMoreStuff(stuff.id).pipe(
          catchError(val => of(`Error`))
        );
      }),
      mergeMap((things) => {
        return from(things).pipe(
          mergeMap((thing) => {
            if (allLocations.some(x => x.id === metaData.id)) {
              return this.service2.getMore(thing.id, thing.type, thing.img_ref);
            }
          }),
          map((thing) => {
          ...
Run Code Online (Sandbox Code Playgroud)

kos*_*kos 5

您需要使用retryor retryWhen(名称非常不言自明) \xe2\x80\x94 这些运算符将重试失败的订阅(一旦发出错误,重新订阅源可观察值。

\n\n

为了提高id在每次重试 \xe2\x80\x94 时引发 ,您可以将其锁定在一个范围内,如下所示:

\n\n

\r\n
\r\n
const { throwError, of, timer } = rxjs;\r\nconst { tap, retry, switchMap } = rxjs.operators;\r\n\r\nconsole.log(\'starting...\');\r\n\r\ngetDetails(0)\r\n  .subscribe(console.log);\r\n\r\n\r\nfunction getDetails(id){\r\n  // retries will restart here\r\n  return of(\'\').pipe(\r\n    switchMap(() => mockHttpGet(id).pipe(\r\n      // upon error occurence -- raise the id\r\n      tap({ error(err){\r\n        id++;\r\n        console.log(err);\r\n      }})\r\n    )),  \r\n    retry(5) // just limiting the number of retries\r\n             // you could go limitless with `retry()`\r\n  )\r\n}\r\n\r\nfunction mockHttpGet(id){\r\n  return timer(500).pipe(\r\n    switchMap(()=>\r\n      id >= 3\r\n      ? of(\'success: \' + id)\r\n      : throwError(\'failed for \' + id)\r\n    )\r\n  );\r\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

请注意,更明智的做法是设置retry仅在出现错误时重试的条件404。这可以通过以下方式实现retryWhen,例如

\n\n
// pseudocode\nretryWhen(errors$ => errors$.pipe(filter(err => err.status === \'404\')))\n
Run Code Online (Sandbox Code Playgroud)\n\n

查看这篇关于 rxjs 中的错误处理的文章,以更加丰富地使用retryretryWhen

\n\n

希望这可以帮助

\n\n
\n\n

更新:还有其他方法可以实现这一点:

\n\n

\r\n
\r\n
const { throwError, of, timer, EMPTY } = rxjs;\r\nconst { switchMap, concatMap, map, catchError, take } = rxjs.operators;\r\n\r\nconsole.log(\'starting...\');\r\n\r\ngetDetails(0)\r\n  .subscribe(console.log);\r\n\r\n\r\nfunction getDetails(id){\r\n  // make an infinite stream of retries\r\n  return timer(0, 0).pipe(\r\n    map(x => x + id),\r\n    concatMap(newId => mockHttpGet(newId).pipe(\r\n      // upon error occurence -- suppress it\r\n      catchError(err => {\r\n        console.log(err);\r\n        // TODO: ensure its 404\r\n\r\n        // we return EMPTY, to continue\r\n        // with the next timer tick\r\n        return EMPTY;\r\n      })\r\n    )),\r\n    // we\'ll be fine with first passed success\r\n    take(1)\r\n  )\r\n}\r\n\r\nfunction mockHttpGet(id){\r\n  return timer(500).pipe(\r\n    switchMap(()=>\r\n      id >= 3\r\n      ? of(\'success: \' + id)\r\n      : throwError(\'failed for \' + id)\r\n    )\r\n  );\r\n}
Run Code Online (Sandbox Code Playgroud)\r\n
<script src="https://unpkg.com/rxjs@6.4.0/bundles/rxjs.umd.min.js"></script>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n