typescript - Kan inte få firstValueFrom/async att fungera med Angular


Jag försöker skapa en Angular (v19) app, som i princip använder ett API och använder svaren för att rendera appens användargränssnitt. Ett ganska standardscenario. Det enda som är mer "djärvt" är att jag skulle vilja initiera en variabel under konstruktionen av appen, så att den är tillgänglig för andra komponenter.

Men problemet är att tjänsten, som jag placerade i konstruktorn, inte får resultaten innan Angular startar de andra stadierna av livscykeln. Samma problem beskrivs här, här och andra.

Mitt första steg var att skapa en tjänst för att använda API:et:

frequency.service.ts

fetchMostRecent(): Observable<Frequency> {
   console.log('FrequencyService.fetchMostRecent');
   return this.httpClient.get<Frequency>(this.baseUrl + '/availability');
}

Och i min komponent försöker jag använda några av de lösningar som föreslagits (toPromise/firstValueFrom/async) i de nämnda inläggen:

app.component.ts

export class AppComponent implements OnInit {
  constructor(private frequencyService: FrequencyService) {
    console.log('constructor');
    this.fetchMostRecentAsync();
  }

  ngOnInit() {
    console.log('ngOnInit');
  }

  async fetchMostRecentAsync() {
    console.log('fetchMostRecentAsync');
    this.mostRecent = await firstValueFrom(this.frequencyService.fetchMostRecent()).then(value => {
      return value);
    });
    console.log('fetchMostRecentAsync: ' + this.mostRecent);
  }
}

Men ngOnInit körs fortfarande innan förfrågan i constructor är slutförd. I konsolen ser anropssekvensen ut så här:

  1. konstruktör
  2. hämtaSenasteAsynkront
  3. FrequencyService.hämtaSenaste
  4. ngOnInit
  5. fetchMostRecentAsync: [objekt Objekt]

Så min fråga är hur jag ska implementera detta korrekt...

Svar #1

Du kan använda en resolver, som kommer att göra exakt vad du vill. Men den blockerar renderingen av komponenten. Därför föreslår jag nedanstående metod.


Vi kan anropa API-anropet på ngOnInit och när API-anropet är slutfört kan vi anropa initialize-metoden som innehåller initialiseringskoden, som beror på API-anropet. Denna metod blockerar inte komponenten från att laddas och väntar också på att API-anropet ska slutföras.

export class AppComponent implements OnInit {
  constructor(private frequencyService: FrequencyService) {
    console.log('constructor');
  }

  ngOnInit() {
    this.fetchMostRecentAsync();
  }

  async fetchMostRecentAsync() {
    console.log('fetchMostRecentAsync');
    this.mostRecent = await firstValueFrom(this.frequencyService.fetchMostRecent())
    console.log('fetchMostRecentAsync: ' + this.mostRecent);
    this.initialize();
  }

  initialize() {
    // ...ngOnInit Logic goes here!
  }
}