Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular - APP_INITIALIZER - Promise vs Observable

I have the application based on Angular v4. The scenario is simple - I need to load some settings from the server before the app starts. To do so, I use the APP_INITIALIZER:

{
  provide: APP_INITIALIZER,
  useFactory: init,
  deps: [SettingsService],
  multi: true
}

export function init(config: SettingsService) {
   return () => config.load_one();
}

//import declarations    
@Injectable()
export class SettingsService {
  constructor(private http: HttpClient) { }

  load_one(): Promise<boolean> {
    return new Promise<boolean>((resolve) => {
        this.http.get('url').subscribe(value => {
            console.log('loadSettings FINISH');
            resolve(true);
        });
    });
  }

  load_two(): Observable<any> {
    const promise = this.http.get('url');

    promise.subscribe(value => {
        console.log('loadSettings FINISH');
    });

    return promise;
  }
}

Somewhere in the app I have the function called manageSettings() (its code doesn't matter at the moment) which requires that the data from the SettingsService service is initialized.

And here's the thing - when I use the the function load_two(), the app does'nt wait until it completes:

app-root constructor
manageSettings()
loadSettings FINISH

and when I use the function load_one() it works fine:

loadSettings FINISH
app-root constructor
manageSettings()

can someone explain why that happens ?

like image 778
Tony Avatar asked Nov 21 '17 20:11

Tony


1 Answers

Angular 12 added support for Observables, so this should no longer be an issue if you're using Angular 12 or newer.

The reason load_one works and load_two doesn't is that Angular 11 and older waits only for Promises; not Observables.

Here's the source:

if (this.appInits) {
    for (let i = 0; i < this.appInits.length; i++) {
        const initResult = this.appInits[i]();
        if (isPromise(initResult)) {
            asyncInitPromises.push(initResult);
        }
    }
}

Where isPromise is defined like this:

export function isPromise<T = any>(obj: any): obj is Promise<T> {
    // allow any Promise/A+ compliant thenable.
    // It's up to the caller to ensure that obj.then conforms to the spec
    return !!obj && typeof obj.then === 'function';
}
like image 67
Kirk Larkin Avatar answered Nov 16 '22 05:11

Kirk Larkin