AngularInDepth уходит от Medium. Эта статья, ее обновления и более свежие статьи размещены на новой платформе inDepth.dev

Angular предоставляет несколько механизмов для подключения к процессу инициализации. В этой статье они исследуются и показано, как их можно использовать.

APP_BOOTSTRAP_LISTENER

Можно зарегистрировать слушателей для процесса начальной загрузки Angular. Вот код, где они называются:

private _loadComponent(componentRef: ComponentRef<any>): void {
  this.attachView(componentRef.hostView);
  this.tick();
  this._rootComponents.push(componentRef);
  // Get the listeners lazily to prevent DI cycles.
  const listeners =
      this._injector.get(APP_BOOTSTRAP_LISTENER, []).concat(this._bootstrapListeners);
  listeners.forEach((listener) => listener(componentRef));
}

Это функция, которую Angular вызывает при создании экземпляра приложения. Помимо понимания того, как компонент добавляется в приложение, он также предполагает, что для каждого загружаемого компонента Angular вызывает прослушиватели, зарегистрированные под токеном APP_BOOTSTRAP_LISTENER, и передает им загруженный компонент.

Это означает, что мы можем использовать такие хуки, чтобы подписаться на процесс начальной загрузки приложения и выполнить нашу логику инициализации. Например, вот как Router подключается к процессу и выполняет некоторую инициализацию.

Поскольку Angular передает инициализированный компонент в обратный вызов, мы можем получить корневой компонент ComponentRef приложения следующим образом:

import {APP_BOOTSTRAP_LISTENER, ...} from '@angular/core';
@NgModule({
  imports: [BrowserModule, ReactiveFormsModule, TasksModule],
  declarations: [AppComponent, BComponent, AComponent, SComponent, LiteralsComponent],
  providers: [{
    provide: APP_BOOTSTRAP_LISTENER, multi: true, useFactory: () => {
      return (component: ComponentRef<any>) => {
        console.log(component.instance.title);
      }
    }
  }],
  bootstrap: [AppComponent]
})
export class AppModule {
}

После того, как я столкнулся с такой функциональностью в источниках, я проверил документацию, она описана как экспериментальная и приводится следующее описание:

Все обратные вызовы, предоставленные с помощью этого токена, будут вызываться для каждого загружаемого компонента. Подпись обратного звонка:

(componentRef: ComponentRef) => void

APP_INITIALIZER

Angular также предоставляет механизм для выполнения некоторой логики инициализации, прежде чем он объявит приложение как инициализированное и продолжит обнаружение изменений и отрисовку шаблона. Вот где происходит инициализация:

constructor(@Inject(APP_INITIALIZER) @Optional() appInits: (() => any)[]) {
  const asyncInitPromises: Promise<any>[] = [];
  if (appInits) {
    for (let i = 0; i < appInits.length; i++) {
      const initResult = appInits[i]();
      if (isPromise(initResult)) {
        asyncInitPromises.push(initResult);
      }
    }
  }

Итак, так же, как мы сделали это для токена APP_BOOTSTRAP_LISTENER, мы просто определяем поставщика APP_INITIALIZER, и наша функция будет вызвана. В следующем примере инициализация Angular задерживается на 5 секунд:

{
  provide: APP_INITIALIZER,
  useFactory: () => {
    return () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve();
        }, 5000);
      });
    }
  },
  multi: true
}

И вы можете определить несколько APP_INITIALIZER’ следующим образом:

{
  provide: APP_INITIALIZER,
  useFactory: () => {
    return () => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve();
        }, 5000);
      });
    }
  },
  multi: true
},
{
  provide: APP_INITIALIZER,
  useFactory: () => {
    return () => {
      return new Promise.resolve(2);
    }
  },
  multi: true
}

BootstrapModule

Еще один момент, когда вы можете подключиться к процессу начальной загрузки приложения, - это bootstrapModule метод:

platform.bootstrapModule(AppModule).then((module) => {
  let applicationRef = module.injector.get(ApplicationRef);
  let rootComponentRef = applicationRef.components[0];
});

Здесь вы можете получить NgModuleRef для модуля начальной загрузки, через который вы можете получить доступ к ApplicationRef и ComponentRef.

Спасибо за прочтение! Если вам понравилась эта статья, нажмите кнопку хлопка под 👏. Это очень много значит для меня и помогает другим людям увидеть историю. Чтобы узнать больше, подпишитесь на меня в Twitter и Medium.