網站搜尋

typescript - Angular - APP_INITIALIZER - Promise 與 Observable


我有一個基於 Angular v4 的應用程式。場景很簡單——我需要在應用程式啟動前從伺服器加載一些設定。為此,我使用了 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;
  }
}

在應用程式的某個地方,我有一個名為 manageSettings() 的函數(其程式碼暫時不重要),該函數需要 SettingsService 服務的資料已初始化。

事情是這樣的——當我使用函數 load_two() 時,應用程式不會等它完成:

app-root constructor
manageSettings()
loadSettings FINISH

當我使用函數 load_one() 時,它運作正常:

loadSettings FINISH
app-root constructor
manageSettings()

有人能解釋為什麼會這樣嗎?

答案#1

Angular 12 增加了對 Observable 的支援,因此如果你使用的是 Angular 12 或更新版本,這應該不再是問題。

原因 load_one 可以工作而 load_two 不行,是因為 Angular 11 及更早版本只等待 Promise;不等待 Observable。

這是來源:

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

其中 isPromise 定義如下:

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';
}