繁体   English   中英

角度“APP_INITIALIZER”在角度4中没有承诺的情况下提供服务?

[英]Angular "APP_INITIALIZER" to have service without promise in angular 4?

我有一个应用程序,它存在于父应用程序的 iframe 中。

当 iFrame 中的应用程序加载时,在我的应用程序 AppModule 中,我有一个名为 tokenService 的 APP_INITIALIZER。 此服务向父应用程序发送 window.sendMessage 以获取令牌。 所以令牌服务中有一个“消息”事件处理程序。

下面是代码:

    import { Injectable } from '@angular/core';
import { ConfigurationService } from './configService';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class tokenService {

  private _configs;
  private msgId = this.newId();
  private messageToGetToken = {
    'id': this.msgId,
    'type': 'test/V/GetToken',
    'data': null
  };

  constructor(private configService: ConfigurationService) {
    this._configs = configService.getConfigurationData();
  }

  getToken() {
    if (this._configs.loginRequired == true) {
      if (window.addEventListener) {
        window.addEventListener('message', this.processMessage, false);
      }
      else {
        (<any>window).attachEvent("onmessage", this.processMessage);
      }

      parent.window.postMessage(JSON.stringify(this.messageToGetToken), '*');

      return Observable.fromEvent(window, 'message')
        .subscribe((messageEvent: MessageEvent) => { this.processMessage(messageEvent); });
    }
  }

  private processMessage(evt) {
    var result = JSON.parse(evt);
    if (result && result.responseFor && result.responseFor === this.msgId) {
      localStorage.setItem('token', result.data ? result.data[0] : null);
      console.log(result.data);
    }
    console.log(evt);
  }

  private newId() {
    return '_' + Math.random().toString(36).substr(2, 9);
  };
}

当结果返回时,将调用方法“processMessage”。

“tokenService”已设置为“APP_INITIALIZER”。 下面是代码:

{
      'provide': APP_INITIALIZER,
      'useFactory': loadService,
      'deps': [ConfigurationService, tokenService],
      'multi': true,
    },

configService 也被初始化:

export function loadConfig(config: ConfigurationService): Function {
  return () => config.configuration$;
}
{
      'provide': APP_INITIALIZER,
      'useFactory': loadConfig,
      'deps': [ConfigurationService],
      'multi': true,
}

在 app.module.ts 文件中,有方法:

export function loadService(tService: tokenService): Function {
  return () => tService.getToken();
}

我不确定如何使这个事件处理程序:“processMessage”作为承诺方法。 任何人都可以帮助我吗? 因为当我尝试运行应用程序时出现错误。 错误是:

ERROR TypeError: tService.getToken is not a function
    at Array.eval (app.module.ts:44)
    at ApplicationInitStatus.runInitializers (core.js:3569)

另外,我想让这个 tokenService 在我的应用程序中的其他组件被初始化之前完成它的执行。 在应用程序继续加载其他组件之前,如何确保 tokenService 已完成执行并调用了 sendMessage 的事件处理程序?

配置服务的代码如下:

    import { Http } from '@angular/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';

import 'rxjs/Rx';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/toPromise';
import 'rxjs/add/operator/catch';

@Injectable()
export class ConfigurationService {
  private configuration;
    constructor(private http: Http) {
    }

    getConfiguration(): Promise<any> {
      let ret = this.http.get('appConfig.json').map(
        res => this.configuration = res.json())
        .toPromise()
        .then((data: any) => {
          this.configuration = data;
        })
        .catch((err: any) => {
          console.log("error while reading app config!");
        });

      return ret.then((x) => {
      });
    }

    getConfigurationData(): any {
      return this.configuration;
    }
}

任何帮助表示赞赏。

提前致谢。

tService.getToken未定义,因为 DI 出错了,而tService实际上是ConfigurationService [ConfigurationService, tokenService]注解表示会注入2个依赖,而工厂函数只有1个参数。

如果它不使用ConfigurationService ,则不必注入它。

getToken已经返回一个 observable。 APP_INITIALIZER期望异步初始化的承诺,因此应将 observable 转换为承诺:

'deps': [tokenService],
  'multi': true,
},

export function loadService(tService: tokenService): Function {
  return () => tService.getToken().toPromise();
}

ConfigurationService的问题在于它是异步的,但它只公开了在某些时候可通过getConfigurationData使用的承诺的结果。 多次调用getConfiguration将导致重复请求。 它应该公开一个可以轻松链接的 promise 或 observable:

export class ConfigurationService {
  public configurationPromise = this.getConfiguration().toPromise();
  public configuration;

  constructor(private http: Http) {
    this.configurationPromise.then(configuration => {
      this.configuration = configuration;
    });
  }

  private getConfiguration(): Observable<any> {
    return this.http.get('appConfig.json').map(res => res.json())
  }
}

然后configurationPromise可以链接到任何地方,它不仅限于 promise 控制流:

export class tokenService {
  ...
  constructor(private configService: ConfigurationService) {}

  getToken(): Observable<any> {
    ...
    return Observable.fromPromise(configService.configurationPromise)
    .switchMap(() => Observable.fromEvent(window, 'message'))
    .map((messageEvent: MessageEvent) => this.processMessage(messageEvent))
    .take(1);
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM