Angular(v5)服务在APP_INITIALIZER promise解析之前构建

Cod*_*ein 14 bootstrapping dependency-injection angular-services angular angular-di

我期待Angular loadConfig()在构建其他服务之前等待我的函数结算,但事实并非如此.

app.module.ts

export function initializeConfig(config: AppConfig){
    return () => config.loadConfig();
}

@NgModule({
     declarations: [...]
     providers: [
          AppConfig,
         { provide: APP_INITIALIZER, useFactory: initializeConfig, deps: [AppConfig], multi: true }
     ] })
export class AppModule {
Run Code Online (Sandbox Code Playgroud)

}

app.config.ts

@Injectable()
export class AppConfig {

    config: any;

    constructor(
        private injector: Injector
    ){
    }

    public loadConfig() {
        const http = this.injector.get(HttpClient);

        return new Promise((resolve, reject) => {
            http.get('http://mycoolapp.com/env')
                .map((res) => res )
                .catch((err) => {
                    console.log("ERROR getting config data", err );
                    resolve(true);
                    return Observable.throw(err || 'Server error while getting environment');
                })
                .subscribe( (configData) => {
                    console.log("configData: ", configData);
                    this.config = configData;
                    resolve(true);
                });
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

一些-其他-service.ts

@Injectable()
export class SomeOtherService {

    constructor(
        private appConfig: AppConfig
    ) {
         console.log("This is getting called before appConfig's loadConfig method is resolved!");
    }
 }
Run Code Online (Sandbox Code Playgroud)

SomeOtherService从服务器接收数据之前调用构造函数.这是一个问题,因为那时的字段SomeOtherService不会设置为正确的值.

如何在确定请求解决SomeOtherService后才确保构造函数被调用loadConfig

Ale*_*esD 5

我还有一个类似的问题是什么解决了我的问题是使用Observable方法和运算符来做所有事情.然后最后只需使用toPromise方法Observable返回一个Promise.这也更简单,因为您不需要自己创建承诺.

AppConfig服务将看起来像这样:

import { Injectable, Injector } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { tap } from 'rxjs/operators/tap';

@Injectable()
export class AppConfig {

    config: any = null;

    constructor(
        private injector: Injector
    ){
    }

    public loadConfig() {
        const http = this.injector.get(HttpClient);

        return http.get('https://jsonplaceholder.typicode.com/posts/1').pipe(
          tap((returnedConfig) => this.config = returnedConfig)
        ).toPromise();
        //return from([1]).toPromise();
    }
}
Run Code Online (Sandbox Code Playgroud)

我在rxjs中使用了新的可管理运算符,这是Google为Angular 5推荐的.tap运算符等同于旧do运算符.

我还在stackblitz.com上创建了一个工作示例,以便您可以使用它.示例链接

  • 嘿@AlesD抱歉,延迟了。我测试了此解决方案,但它不起作用。它进入了`loadConfig`,但在返回HTTP请求之前仍在我的应用程序中加载了其他服务。 (5认同)