21

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 ?

1 Answer 1

33

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';
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is there any difference between these two approaches? I mean the angular team hasn't deprecated the use of Promise over Observable yet. So, suppose if we are already using Promise then is there a reason that we should get change it to the Observable now?
@Himanshu There's no real reason to move to Observable if you're already using Promise. The change makes it more convenient to avoid a manual conversion from an existing Observable to a Promise. You can see for yourself in the source, where Angular just converts the Observable into a Promise for you.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.