angular - Hur man ignorerar svaret från en Observable


Med hjälp av Observable.timer(0, 1000) gör jag kontinuerliga förfrågningar till min server i ett definierat tidsmönster. Efter att jag har bearbetat innehållet i svaret är det under speciella omständigheter och beroende av det föregående svaret möjligt att jag behöver släppa svaret och därför inte skicka det vidare till prenumeranten av tjänsten:

@Injectable()
export class LoggerService {
  constructor(private http: Http) { }
  private apiURL = 'assets/file.json'; 

  getList() {
    return Observable.timer(0, 1000)
      .concatMap(() => this.http.get(this.apiURL))
      .map(this.extractData)
      .catch(this.handleError););
  }
  private extractData(res: Response) {
    var fooot = new Foo();
    fooot.fillFromJSON(JSON.stringify(res.json()));
    if(fooot.getProperty()){
    //DROP IT
    }
    return fooot;
  }

  private handleError(error: any) {
    let errMsg = (error.message) ? error.message :
      error.status ? `${error.status} - ${error.statusText}` : 'Server error';
    console.error(errMsg);
    return Observable.throw(errMsg);
  }
}

Metoden getList() anropas sedan från ngOnInit i en komponent. För närvarande finns det två möjliga lösningar jag kan tänka på, men kanske finns det ett bättre/tydligare sätt att lösa detta problem:

  1. Om jag måste släppa svaret skapar jag ett speciellt objekt som känns igen av prenumeranten av getList() och sedan hanteras specifikt. Men denna lösning skulle vara väldigt ful eftersom det släppta svaret lämnar min tjänst och jag behöver skriva extra kod utanför tjänsten för att hantera detta fall.

  2. Jag kastar ett undantag när jag måste släppa svaret. Sedan fångas undantaget, identifieras (för att skilja det från andra fall) och sedan släpps det utan någon notis/utmatning. Därefter startas observabeln om. Fördelen med detta tillvägagångssätt är att observabeln som bör släppas inte lämnar tjänsten, men jag gillar inte användningen av undantag i detta fall för kontrollflödet.

Jag har provat båda lösningarna och de fungerar, men jag hoppas att det finns bättre metoder.

Svar #1

Om jag förstår rätt, letar du efter switchMap-operatören.

Om inget svar kommer inom 1 sekund (det angivna intervallet) avbryts HTTP-förfrågan tyst, och en ny påbörjas.

Uppdatering :

Om du vill avbryta HTTP-förfrågan manuellt måste du skapa en cancelSubject: Subject och definiera en takeUntil(cancelSubject) på HTTP-förfrågan.

För att avbryta HTTP-förfrågan, kallar du helt enkelt på cancelSubject.next(true), vilket i sin tur kommer att avbryta HTTP-förfrågan, eftersom takeUntil träder i kraft.

Tänk på att efter en sekund kommer förfrågan att startas om. Om du vill avbryta timern måste du sätta .takeUntil(cancelSubject) på den yttre observablerna.

Svar #2

Jag slutade med att använda distinctUntilChanged för att uppnå mitt mål:

getList() {
    return Observable.timer(0, 1000)
      .concatMap(() => this.http.get(this.apiURL)
      .distinctUntilChanged(null, x => x.json().info[1].value)
      .map(this.extractData)
      .catch(this.handleError);
  }

Därför, om den nuvarande och den senaste responsen delar samma specifika värde, tas den nyaste responsen bort. Jag antar att min fråga inte var tillräckligt tydlig och jag nämnde inte att beslutet att ta bort en respons beror på den föregående.

En nackdel med detta tillvägagångssätt är att svaret måste analyseras två gånger, men jag antar att det inte kan undvikas. Det vore trevligt att veta om json-metoden är snabbare än en fullständig strängjämförelse av resultatet (body).

Om beslutet att bortse från ett svar endast beror på det aktuella svaret, skulle jag rekommendera att använda ett filter.