【问题标题】:How can I make Angular 5 wait for a Promise used inside an Injectable's constructor to resolve before constructing dependants - or ngOnInit?如何让 Angular 5 在构造依赖项或 ngOnInit 之前等待 Injectable 构造函数中使用的 Promise 解析?
【发布时间】:2018-05-12 05:33:20
【问题描述】:

我的 Angular 5 项目中有一个服务,它拥有一些配置状态:

@Injectable
export class FooService {

    isIncognito: boolean = null;

    constructor() {

        // I want Angular to wait for this to resolve (i.e. until `isIncognito != null`):
        FooService.isIncognitoWindow()
            .then( isIncognito => {

                this.isIncognito= isIncognito;
            } );
    }


    private static isIncognitoWindow(): Promise<boolean> {
    // https://stackoverflow.com/questions/2909367/can-you-determine-if-chrome-is-in-incognito-mode-via-a-script
    // https://developer.mozilla.org/en-US/docs/Web/API/LocalFileSystem

        return new Promise<boolean>( ( resolve, reject ) => {

            let rfs = window['requestFileSystem'] || window['webkitRequestFileSystem'];
            if( !rfs ) {
                console.warn( "window.RequestFileSystem not found." );
                resolve( false );
            }

            const typeTemporary = 0;
            const typePersistent = 1;

            // requestFileSystem's callbacks are made asynchronously, so we need to use a promise.
            rfs(
                /*type: */ typeTemporary,
                /* bytesRequested: */ 100,
                /* successCallback: */ function( fso: WebKitFileSystem ) {

                    resolve( false );
                },
                /* errorCallback: */ function( err: any /* FileError */ ) {

                    resolve( true );
                }
            );
        } );
    }
}

我的项目中的许多组件都使用此服务,并作为构造函数参数传递。例如:

@Component( {
    moduleId: module.id,
    templateUrl: 'auth.component.html'
} )
export class AuthComponent implements OnInit {

    constructor( private fooService: FooService ) {
    }

    ngOnInit(): void {

        // do stuff that depends on `this.fooService.isIncognito != null`
    }
}

理想情况下,我希望 Angular 在将 FooService 注入其他组件之前先等待 FooService::isIncognitoWindow() 承诺解决(解决立即发生,但不是同步发生)。

另一种解决方案是将FooComponent.isIncognito 的属性更改为Promise&lt;boolean&gt; 并再次解析它并通过回调调用ngOnInit 的其余部分,但这意味着每个组件都会导致再次调用promise 的主函数- 所以这意味着可能将其更改为缓冲的 Observable 或 Subject ,这变得不必要的复杂 - 所有这些都针对单个 boolean 值。这也意味着重构大量我不想做的代码。

【问题讨论】:

  • 您可以在应用程序启动之前使用 APP_INITIALIZER 令牌来解析 isIncognito 值,然后在接下来的值中解析组件/服务
  • @David 这听起来很有希望——你能用一个简短的例子在答案中重新发布吗?这样我就可以接受了。

标签: angular promise


【解决方案1】:

您可以做的是使用APP_INITIALIZER 令牌来确保您的FooService 在应用程序启动之前被初始化。使用下面的代码,只有当 load 方法返回的承诺已经解决时,Angular 才会启动应用程序。

FooService.ts

@Injectable()
export class FooService {

    isIncognito: boolean = null;

    public load()// <=== the method to be called and waited on during initialiation
  {
      return FooService.isIncognitoWindow().then(isIncognito =>
      {
        this.isIncognito = isIncognito;
      });

  }

    private static isIncognitoWindow(): Promise<boolean> {
    { //your method here

app.module.ts

export function loadFooService(fooService: FooService): Function 
{
  return () => { return fooService.load() }; 
}


@NgModule({
  imports:      [ BrowserModule, FormsModule ],
  declarations: [ AppComponent, HelloComponent ],
  bootstrap:    [ AppComponent ],

  providers: [ FooService,
  { provide: APP_INITIALIZER, useFactory:loadFooService , deps: [FooService], multi: true },]
})

stackblitz example

【讨论】:

【解决方案2】:

如果isIncognitoWindow 返回Promise,试试这个:

      await awaitFooService.isIncognitoWindow()
            .then( isIncognito => {
                this.isIncognito= isIncognito;
            } );

【讨论】:

  • 您不应同时使用awaitthen。择其一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-10
  • 2023-01-18
  • 1970-01-01
  • 2016-12-30
  • 2021-06-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多