typescript - APP_INITIALIZER leder till en tom sida utan fel i Angular 12 (fungerade från Version 9 till 11)


Vi behöver några tjänster i vår applikation redan från början. Därför har vi några leverantörer som initialiserar dem vid uppstart. Detta är från providers-sektionen i app.module.ts:

providers: [
  { provide: MAT_DATE_LOCALE, useValue: 'en-US' },
  {
    provide: APP_INITIALIZER,
    useFactory: (service: MetaService) => () => service,
    deps: [MetaService],
    multi: true
  }
],

Detta fungerade bra i Angular 9-11. Men efter uppgradering till Angular 12 och till och med i ett blankt Angular 12-projekt verkar detta bryta applikationen.

Tjänsten är dock skapad. Den loggas korrekt med detta:

useFactory: (service: MetaService) => () => { console.log(service); return service; },

Men sidan kommer tillbaka som en blank vit. Inga komponenter renderas, ingen routing har skett.

Det finns inga fel på CLI och inget i webbläsarens konsol, bara en tom sida. När jag tar bort leverantören verkar det fungera bra.

Har de ändrat hur APP_INITIALIZER fungerar i Angular 12? Hur fixar eller uppdaterar man koden för att få den att fungera igen? Kanske finns det ändå ett bättre sätt att initiera tjänster vid start?

Svar #1

Angular ändrade sin app-initializer-funktionalitet för att tillåta både Observables och Promises. Vad som också har ändrats är specificiteten för injektionstoken, som förväntar sig en funktion som returnerar ett löfte, en observable eller void. Så för tillfället är din kod dålig eftersom du returnerar en tjänst istället för en av de förväntade typerna. Det förklarar fortfarande inte vad som går fel.

Angular brukade bara kontrollera om fabriksfunktionen för varje initializer returnerade ett löfte och lade till det i en lista över löften att köra med Promise.all(). Nu kontrollerar det också om det är ett observable och konverterar det till ett löfte genom att kapsla in ett subscribe-anrop i ett löfte och koppla ihop complete- och error-callbacks från Observable med resolve- och reject-callbacks från löftet.

Om du har en metod som heter subscribe på din tjänst, skulle detta göra att din tjänst passerar Angulars isSubscribable-kontroll. Då skulle Angular behandla din tjänst som ett Observable och försöka konvertera det till ett löfte på det sätt som nämnts ovan. (Om du har en then-metod skulle det också orsaka ett problem, även om det är osannolikt eftersom din kod fungerade tidigare). Löftet skulle aldrig lösas och det skulle leda till det beteende du beskriver.

Det finns ingen annan anledning jag kan föreställa mig som skulle orsaka detta problem med tanke på koden du har delat. Åtminstone ändra fabriksdefinitionen så att den returnerar void och du borde vara klar.

useFactory: (service: MetaService) => () => { }