Как заставить Angular 5 ждать разрешения Promise, используемого внутри конструктора Injectable, прежде чем создавать зависимости - или ngOnInit? - PullRequest
0 голосов
/ 11 мая 2018

В моем проекте 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> {
    // /1490063/mozhete-li-vy-opredelit-nahoditsya-li-chrome-v-rezhime-inkognito-s-pomoschy-stsenariya
    // 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::isIncognitoWindow() (разрешение происходит мгновенно, но не синхронно), прежде чем вводить FooService в другие компоненты.

Альтернативное решение - изменить свойство FooComponent.isIncognito на Promise<boolean>, разрешить его снова и вызвать остальную часть ngOnInit с помощью обратного вызова, но это означает, что каждый компонент вызовет повторную активацию основной функции обещания. - таким образом, это означает, что вместо этого можно изменить его на буферизованный Observable или Subject, и это становится излишне сложным - все для одного значения boolean. Это также означает рефакторинг большого количества кода, который я бы предпочел не делать.

Ответы [ 2 ]

0 голосов
/ 11 мая 2018

Что вы можете сделать, это использовать токен APP_INITIALIZER, чтобы убедиться, что ваш FooService инициализирован перед запуском приложения. С помощью приведенного ниже кода angular будет запускать приложение только после разрешения обещания, возвращенного методом load.

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

0 голосов
/ 11 мая 2018

Если isIncognitoWindow возвращает Promise, попробуйте это:

      await awaitFooService.isIncognitoWindow()
            .then( isIncognito => {
                this.isIncognito= isIncognito;
            } );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...