Angular: Ленивые загрузочные модули с сервисами
Я следовал этому уроку, чтобы понять ленивую загрузку, и ниже мой вывод.
Сценарий 1: Услуги предоставляются путем помещения их в providers
массив дочернего модуля
Сценарий 2. Услуги предоставляются в дочернем модуле с использованием forRoot
подход
Со сценарием 1 в контексте,
- Если дочерний модуль загружен с нетерпением, экземпляр службы добавляется в корневой инжектор.
- Если дочерний модуль загружается лениво, экземпляр службы добавляется в корневой инжектор, а новый экземпляр службы добавляется в дочерний инжектор, что не является обычным вариантом использования.
Со сценарием 2 в контексте,
Если дочерний модуль загружен с нетерпением, экземпляр службы добавляется в корневой инжектор.
Если дочерний модуль загружается лениво, один и тот же экземпляр службы доступен как в корневом, так и в дочернем модулях, что является обычным вариантом использования.
Они упомянули следующее.
В начале,
Таким образом, даже при использовании модулей не может быть "частной" службы, если... модуль загружается с отложенной загрузкой.
В заключение,
Хотя этот синтаксис немного более сложен, чем оригинал, он гарантирует нам, что в корневой модуль добавлен только один экземпляр CreditCardService. Когда CreditCardModule загружен (даже загружен ленивым), новый экземпляр этой службы не будет добавлен к дочернему инжектору.
Если экземпляр будет доступен и в корневом инжекторе, как они говорят, что служба "приватизирована"?
Я не совсем понимаю. Кто-то, пожалуйста, уточните.
4 ответа
providedIn: 'root'
это самый простой и эффективный способ предоставления услуг, начиная с Angular 6:
- Служба будет доступна для всего приложения в виде отдельного файла, без необходимости добавлять его в массив поставщиков модуля (например, Angular <= 5).
- Если служба используется только в модуле с отложенной загрузкой, она будет загружаться с отложенным модулем
- Если он никогда не используется, он не будет содержаться в сборке (дерево потрясено).
Для получения дополнительной информации рассмотрите чтение документации и часто задаваемых вопросов по NgModule.
Btw:
- Если вы не хотите использовать одноэлементное приложение для всего приложения, используйте вместо него массив поставщика.
- Если вы хотите ограничить область действия, чтобы никакой другой разработчик никогда не использовал вашу службу за пределами определенного модуля, используйте вместо этого массив поставщика NgModule.
Эта ветка довольно старая, но я отвечу на то, что узнал, когда искал в этой теме будущих спотыкателей в этой теме.
Концепция приватизации службы с отложенной загрузкой является правильной и по следующим причинам:
- Когда модуль загружается лениво, он создает собственный контекст Injector, который является дочерним для корневого инжектора (точнее, его родительского инжектора). Службы в них не будут отправлены в корневой инжектор, так как они не были созданы при настройке корневого инжектора.
Angular Doc говорит, что один из способов охвата ваших услуг - предоставить их своему собственному модулю (предположим, Module-A). И только когда любой другой модуль B импортирует модуль A, он будет иметь поставщика этой услуги (из модуля A) и, таким образом, сможет получить к нему доступ. Это на самом деле работает для ленивых модулей, а не для активных модулей по следующим причинам:
Когда вы реализуете описанный выше метод определения объема для активных модулей, он создаст провайдера для служб этого модуля (предположим, модуль A). Но когда этот конкретный модуль "А" импортируется в корневой модуль (как и все активные модули), корневой инжектор создаст один экземпляр этой службы и откажется от любого дублированного экземпляра этой службы в области действия корневого инжектора (если модуль A был импортирован в любой другой модуль) Таким образом, все активные модули имеют доступ к одноэлементному сервису любого модуля, который был импортирован в корневой модуль.
- Снова при загрузке приложения корневой инжектор и модуль не будут знать о ленивом модуле и его сервисах. Таким образом, ленивые сервисы приватизируются в своем собственном модуле. Теперь, чтобы корневой модуль имел доступ к отложенному сервису, он должен следовать угловому способу импорта модуля. Который в основном импортирует модуль "предполагается, что он лениво загружен" в корневой модуль во время загрузки приложения, и, таким образом, побеждает цель ленивой загрузки.
Если вы все еще хотите иметь доступ к отложенному сервису из корневого инжектора. Вы можете использовать:
@Injectable({ providedIn: 'root' })
декоратор в ленивом сервисе и закачка его в корневой инжектор без загрузки ленивого модуля при загрузке приложения.
Пример, который вы использовали, не является истинной реализацией отложенной загрузки, если у вас есть доступ к отложенным службам в корневом модуле без providedIn: root
объект. Вы можете перейти по этой ссылке: https://angular.io/guide/providers
Вот как я это делаю: https://stackblitz.com/edit/angular-lazy-service-module?file=src%2Fapp%2Fapp.component.ts
Это доказательство концепции. Вам нужно следить за тем, какой инжектор вы используете (в случае, если ленивому сервису нужны некоторые зависимости) и как вы управляете жизненным циклом ленивого загруженного сервиса (сколько экземпляров вы создаете и т. Д.).
Мой пример использования заключается в том, что существует довольно большой сервис (экспорт в Excel, более 400 КБ gziped), который используется во многих областях приложения, но я не хочу загружать / анализировать его, пока он действительно не понадобится - более быстрая начальная загрузка! (Я также использовал стратегию предварительной загрузки с задержкой, которая загружает модули через несколько секунд).
Основная идея заключается в том, что вы определяете его как ленивый модуль на маршруте (который вы на самом деле не используете), но вы запускаете загрузку вручную. Вы также разрешаете службу из этого модуля (если она у вас есть) с помощью токена инъекции.
ленивый модуль
import { NgModule } from '@angular/core';
import { LazyService } from './lazy-service.service';
import { LAZY_SERVICE_TOKEN } from './lazy-service.contract';
@NgModule({
providers: [{ provide: LAZY_SERVICE_TOKEN, useClass: LazyService }],
})
export class LazyServiceModule {
}
ленивый сервис
import { Injectable } from '@angular/core';
import { LazyService as LazyServiceInterface } from './lazy-service.contract';
@Injectable()
export class LazyService implements LazyServiceInterface {
process(msg: string) {
return `This message is from the lazy service: ${msg}`;
}
}
модуль приложения
@NgModule({
imports: [BrowserModule,
RouterModule.forRoot([
// whatever other routes you have
{
path: '?$lazy-service', //some name that will not be used
loadChildren: 'app/lazy-service/lazy-service.module#LazyServiceModule',
},
])],
declarations: [AppComponent],
bootstrap: [AppComponent]
})
export class AppModule { }
используя его внутри компонента
constructor(
private loader: NgModuleFactoryLoader,
private injector: Injector,
) {
}
async loadServiceAndCall() {
const factory = await this.loader.load('app/lazy-service/lazy-service.module#LazyServiceModule');
const moduleRef = factory.create(this.injector);
const service: LazyService = moduleRef.injector.get(LAZY_SERVICE_TOKEN);
this.value = service.process('"from app.component.ts"')
}
Лучшее объяснение, которое я могу вам дать, находится в этой статье.
Во всяком случае, вкратце:
- Все модули объединяются на этапе компиляции.
- При активной загрузке Angular Compiler все сервисы помещаются в rootInjector, что делает сервис доступным для всего приложения.
- Если более одного модуля предоставляют услугу с одним и тем же токеном, поставщик, определенный в модуле, который импортирует другие модули, всегда побеждает.
- Поставщик из последнего импортированного модуля переопределяет поставщиков в предыдущих модулях, за исключением модуля, который их импортирует.
- При lazyLoaded каждый модуль все еще объединяется в один при компиляции, но для каждого модуля создается инжектор. Исходя из этого, существует иерархия инжекторов, и то, как компонент ищет введенный токен, поднимается по иерархии в поисках ближайшего поставщика для этого токена.
- forRoot () * это только соглашение, используемое, когда у вашего модуля есть сервисы, которые вы хотите предоставить для всего приложения и других только для дочерних элементов какого-либо модуля.
Для Lazy загрузки услуг вы можете проверить ниже ссылку