• retryWhen
    • 签名: retryWhen(receives: (errors: Observable) => Observable, the: scheduler): Observable
  • 当发生错误时,基于自定义的标准来重试 observable 序列。
    • 示例
      • 示例 1: 在指定的时间间隔后触发重试
      • 示例 2: 时间间隔增加的自定义重试
  • 其他资源

    retryWhen

    签名: retryWhen(receives: (errors: Observable) => Observable, the: scheduler): Observable

    当发生错误时,基于自定义的标准来重试 observable 序列。

    retryWhen - 图1

    示例

    示例 1: 在指定的时间间隔后触发重试

    ( jsBin |
    jsFiddle )

    1. import { timer } from 'rxjs/observable/timer';
    2. import { interval } from 'rxjs/observable/interval';
    3. import { map, tap, retryWhen, delayWhen } from 'rxjs/operators';
    4. // 每1秒发出值
    5. const source = interval(1000);
    6. const example = source.pipe(
    7. map(val => {
    8. if (val > 5) {
    9. // 错误将由 retryWhen 接收
    10. throw val;
    11. }
    12. return val;
    13. }),
    14. retryWhen(errors =>
    15. errors.pipe(
    16. // 输出错误信息
    17. tap(val => console.log(`Value ${val} was too high!`)),
    18. // 5秒后重启
    19. delayWhen(val => timer(val * 1000))
    20. )
    21. )
    22. );
    23. /*
    24. 输出:
    25. 0
    26. 1
    27. 2
    28. 3
    29. 4
    30. 5
    31. "Value 6 was too high!"
    32. --等待5秒后然后重复此过程
    33. */
    34. const subscribe = example.subscribe(val => console.log(val));
    示例 2: 时间间隔增加的自定义重试

    (
    StackBlitz
    )

    归功于 Maxim Koretskyi 的优化

    1. import { Observable } from 'rxjs/Observable';
    2. import { _throw } from 'rxjs/observable/throw';
    3. import { timer } from 'rxjs/observable/timer';
    4. import { mergeMap, finalize } from 'rxjs/operators';
    5. export const genericRetryStrategy = ({
    6. maxRetryAttempts = 3,
    7. scalingDuration = 1000,
    8. excludedStatusCodes = []
    9. }: {
    10. maxRetryAttempts?: number,
    11. scalingDuration?: number,
    12. excludedStatusCodes?: number[]
    13. } = {}) => (attempts: Observable<any>) => {
    14. return attempts.pipe(
    15. mergeMap((error, i) => {
    16. const retryAttempt = i + 1;
    17. // 如果达到最大重试次数或响应的状态码
    18. // 不是我们想重试的,就抛出错误
    19. if (
    20. retryAttempt > maxRetryAttempts ||
    21. excludedStatusCodes.find(e => e === error.status)
    22. ) {
    23. return _throw(error);
    24. }
    25. console.log(
    26. `Attempt ${retryAttempt}: retrying in ${retryAttempt *
    27. scalingDuration}ms`
    28. );
    29. // 重试的时间间隔不断增长: 1秒、2秒,以此类推
    30. return timer(retryAttempt * scalingDuration);
    31. }),
    32. finalize(() => console.log('We are done!'))
    33. );
    34. };
    1. import { Component, OnInit } from '@angular/core';
    2. import { catchError, retryWhen } from 'rxjs/operators';
    3. import { of } from 'rxjs/observable/of';
    4. import { genericRetryStrategy } from './rxjs-utils';
    5. import { AppService } from './app.service';
    6. @Component({
    7. selector: 'my-app',
    8. templateUrl: './app.component.html',
    9. styleUrls: [ './app.component.css' ]
    10. })
    11. export class AppComponent implements OnInit {
    12. constructor(private _appService: AppService) {}
    13. ngOnInit() {
    14. this._appService
    15. .getData(500)
    16. .pipe(
    17. retryWhen(genericRetryStrategy()),
    18. catchError(error => of(error))
    19. )
    20. .subscribe(console.log);
    21. // 排除状态码,增加延迟以保持日志清晰
    22. setTimeout(() => {
    23. this._appService
    24. .getData(500)
    25. .pipe(
    26. retryWhen(genericRetryStrategy({
    27. scalingDuration: 2000,
    28. excludedStatusCodes: [500]
    29. })),
    30. catchError(error => of(error))
    31. )
    32. .subscribe(e => console.log('Exluded code:', e.status));
    33. }, 8000);
    34. }
    35. }

    其他资源

    • retryWhen :newspaper: - 官方文档
    • 错误处理操作符: retry 和 retryWhen :video_camera: :dollar: - André Staltz

    :file_folder: 源码: https://github.com/ReactiveX/rxjs/blob/master/src/internal/operators/retryWhen.ts