Действовать, когда лениво загруженный модуль уничтожен

У меня есть приложение Angular 6, и мне лень загружать модуль и передавать некоторые данные через маршрутизатор. Оказавшись в модуле, я вызываю метод в общей службе, которому я передаю эти данные (материал конфигурации).

Мне нужно вызвать метод, когда этот модуль уничтожен (по сути, когда пользователь покидает этот путь), но я хочу вызвать его только один раз, поэтому я хочу избежать постоянного наблюдения за изменением маршрута, поскольку это будет дорого. Причина в том, что мне нужно сбросить конфигурацию общего сервиса. По сути, у меня есть определенные данные конфигурации для приложения, и мне нужно переопределить их для модуля с ленивой загрузкой, но вернуть их, когда пользователь не находится в модуле.

Я пытаюсь вызвать функцию на хуке OnDestroy модуля, но она не запускается.

Модуль маршрутизации:

const appRoutes: Routes = [
    {
        path: 'lazy',
        loadChildren: 'lazy.module#LazyModule',
        data: {
            test: 'data'
        }
    },
    {
        path: 'home',
        loadChildren: 'home.module#HomeModule',
    },
{
        path: '**',
        redirectTo: '/home'
    }
]

Ленивая загрузка модуля:

export class LazyModule implements OnDestroy {

    constructor() {
        console.warn('LazyModule launched!'); // I see this
    }

    ngOnDestroy() {
        console.warn('destroyed'); // This is not triggered
    }

}

person bubble    schedule 29.08.2018    source источник
comment
Я не думаю, что этот хук вызывается для @NgModules только для @Directives/@Components. В любом случае он вообще не будет вызываться, поскольку ленивый модуль не уничтожается, когда вы уходите от него. Он остается доступным, что позволяет повторно посещать его маршруты без перезагрузки. Конструктор вызывается, потому что его обеспечивает JavaScript, но onDestroy — это хук фреймворка. Объясните, почему вы хотите это сделать. Я не вижу мотивации, но, скорее всего, это проблема XY.   -  person Aluan Haddad    schedule 29.08.2018
comment
Я отредактировал свой вопрос, чтобы объяснить свою мотивацию. У меня есть некоторые данные конфигурации приложения. Я настраиваю общую службу с этими данными, но их необходимо перезаписать, когда общая служба используется из модуля с отложенной загрузкой. Как только пользователь покидает модуль, глобальную конфигурацию приложения необходимо вернуть в общий модуль. Может есть способ принудительно уничтожить модуль?   -  person bubble    schedule 29.08.2018
comment
@bubble Я обновил свой ответ, чтобы отразить изменения в вопросе.   -  person Reactgular    schedule 29.08.2018


Ответы (2)


Начиная с Angular 6, модули никогда не выгружаются.

Маршрутизатор в настоящее время не проверяет, был ли модуль уничтожен после его ленивой загрузки. Таким образом, даже если вы получите NgModuleRef и вызовете destroy вручную, маршрутизатор все равно будет считать, что он загружен. Так что не будет лениво загружать его во второй раз.

Маршрутизатор просто загружает модуль, но не управляет его жизненным циклом. Даже если бы вы могли уничтожить модуль, это не освободило бы много памяти. Модули с ленивой загрузкой управляются пакетами WebPack, загружаемыми с помощью SystemJS. После загрузки они остаются в памяти. Даже если Angular уничтожит экземпляр модуля, исходный код пакета все еще находится в кеше памяти SystemJS загруженных пакетов.

Эта проблема распространяется на библиотеки поставщиков. Если у вас есть лениво загруженный модуль, который использует стороннюю графическую библиотеку, такую ​​как D3, то эта библиотека поставщика будет загружена, и вы не сможете ее выгрузить.

Если вам нужны провайдеры, которые существуют только для определенных маршрутов, вам следует использовать провайдеров представлений.

@Component({
     ...
     viewProviders: [
         LazyFeatureService
     ]
})
export class MyLazyComponent {}

Когда вы используете вышеупомянутый компонент в качестве компонента маршрутизатора, тогда служба LazyFeatureService создается, когда модуль загружается отложенно, но когда компонент уничтожается, служба также уничтожается. В следующий раз, когда пользователь посетит ленивый маршрут, сервис будет создан снова.

Обновление:

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

Этого можно добиться, используя обработчики canActivate и canDeactivate в маршруте.

В конфигурации маршрута для ленивого модуля создайте маршрут верхнего уровня для обработки активаций.

const routes: Routes = [
    {
        path: '',
        canActivate: [ConfigActivator],
        canDeactivate: [ConfigActivator],
        children: [
            // move the routes here
        ]
    };

Затем вы можете определить активатор следующим образом.

 @Injectable()
 export class ConfigActivator implement CanActivate, CanDeactivate<any> {
       public constructor(private config: MyConfigService) {
       }

       public canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
           this.config.lazyModuleLoaded();
           return true;
       }

       public canDeactivate(component: any, currentRoute: ActivatedRouteSnapshot, currentState: RouterStateSnapshot, nextState?: RouterStateSnapshot): boolean {
           this.config.lazyModuleUnloaded();
           return true;
       }
 }

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

person Reactgular    schedule 29.08.2018

Модули не уничтожаются после отложенной загрузки, но вы можете реализовать OnDestroy для компонента, который загружает модуль.

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

Какой компонент содержит

<router-outlet></router-outlet>

И в TypeScript для этого компонента реализуйте OnDestroy, и он вызовет метод ngOnDestroy.

person Adrian Brand    schedule 29.08.2018