angular - Rxjs försök om med fördröjningsfunktion


Jag försöker använda retry med delay-funktionen, jag förväntar mig att funktionen ska anropas efter 1000 ms försening, men det gör den inte, vad kan vara felet här? Titta på konsolens utskrift, det är samma tid 16:22:48.

Jag förväntar mig där 16:22:48, 16:22:59 ...

canCreate: boolean;
getSomeFunction(): Observable<boolean> {
        return new Observable<boolean>(
            observer => {
                const canCreate = null; // this is just null for now, will some value later
                if (canCreate == null) {
                    observer.error('error');
                } else {
                    observer.next(true);
                }
                observer.complete();
            }
        )
    }


this.getSomeFunction()
      .do((value) => {
        this.cCreate = value;
      }, (error) => {
         console.log(error + new Date().toTimeString());
      })
      .delay(1000)
      .retry(10)
      .subscribe(
        value => this.cCreate = value,
        error => {
          this.cCreate = false;
        },
        () => {}
      );
  }

och konsolresultatet är :

Svar #1

delay() används för att införa en fördröjning mellan händelser som emitteras av observablen. Men observablen emitterar aldrig någon händelse. Den ger bara fel direkt.

Det du letar efter är retryWhen(), vilket låter dig bestämma efter hur lång tid du ska försöka igen:

RxJS 5:

  .retryWhen(errors => errors.delay(1000).take(10))

RxJS 6:

import { retryWhen, delay, take } from 'rxjs/operators'
someFunction().pipe(
  // ...
  retryWhen(errors => errors.pipe(delay(1000), take(10)))
)

Detta kommer att slutföra hela observabeln efter 10 försök. Om du vill att hela observabeln ska ge ett fel efter 10 försök måste observabeln som returneras av retryWhen-callbacken kasta:

RxJS 5:

  .retryWhen(errors => errors.delay(1000).take(10).concat(Observable.throw()))

RxJS 6:

import { retryWhen, delay, take, concatMap, throwError } from 'rxjs/operators'
someFunction().pipe(
  // ...
  retryWhen(errors => errors.pipe(delay(1000), take(10), concatMap(throwError)))
)

Svar #2

Eftersom det accepterade svarens förslag att använda retryWhen() var okej vid den tiden, är denna operator nu, som vi kan se på den angivna länken för retryWhen(), föråldrad och kommer att tas bort från och med RxJS version 9 eller 10. Så alla lösningar med retryWhen() är också föråldrade.

Nu är en lösning som föreslås av RxJS-utvecklingsteamet och dokumentationen att använda retry()-operatorn, som också är en felhanteringsoperator, med parametern retryConfig.

Nu, för att uppnå samma logik, med mindre kod, skulle du använda följande:

// A custom method to check should retry a request or not
shouldRetry(error: HttpErrorResponse) {
    // Example for catching specific error code as well
    if (error.status === 503) {
      return timer(1000); // Adding a timer from RxJS to return observable to delay param.
    }

    throw error;
  }

// Retry operator somewhere in your code
retry({ count: 2, delay: this.shouldRetry })

Som du kunde se från exemplet ovan har vi använt mindre kod och färre RxJS-operatörer för att uppnå viss logik för vilken vi tidigare behövde mycket mer med retryWhen()-operatören. Detta är också anledningen till att teamet avvecklar denna operatör, eftersom samma logik kan uppnås med retry() med denna konfiguration.

Observera: du skulle behöva anpassa koden jag tillhandahöll efter dina behov, men detta är ett exempel på hur man använder retry() -operatorn istället för retryWhen().

Svar #3

För att bygga vidare på @JB Nizets svar. Om du skriver detta i rxjs 5+ med lettable-operatörer, strukturera det som

retryWhen(errors => errors.pipe(delay(1000), take(5)))

Svar #4

Försök igen 5 gånger med en fördröjning på 500 ms:

RxJS 6.x

  • Använd index för att räkna
  • Transformera retryWhens fel-Observable till timer eller throwError
retryWhen(concatMap((err, index) => index < 5 ? timer(500) : throwError(err)))

RxJS 6.3 ⬆

  • Använd index för att räkna
  • I retryWhen 's fel-Observable, använd delayWhen för att vänta timer eller throwError
retryWhen(delayWhen((err, index) => index < 5 ? timer(500) : throwError(err)))

eller så kan du göra detta :

const delayFn = (delay = 0, count = Infinity) => {
    return (err, index) => index < count ? timer(delay) : throwError(err);
};
retryWhen(concatMap(delayFn(500, 5))) // RxJS 6.x
retryWhen(delayWhen(delayFn(500, 5))) // RxJS 6.3 ⬆

RxJS 7.3 ⬆

  • Bara försök igen
retry({ count: 5, delay: 500 })

Relaterade artiklar