Ленивая загрузка  —  это техника загрузки чего-то по требованию.

Она применяется к различным уровням процесса разработки приложений  —  от модулей до компонентов. Ленивая загрузка на уровне модулей довольно известна в мире Angular, но о второй говорят меньше. В статье мы создадим компоненту аккордеон и лениво загрузим её содержимое.

Зачем загружать компоненты лениво?

Фото Dave Willhite на Unsplash

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

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

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

Первоначальная версия

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

Есть две компоненты:

  1. Post, загружающая данные сообщения в блоге.
  2. Аккордеон.

Используем их для визуализации сообщения в блоге пользователям в app-component.

Используем компоненту app-accordion и передаем ей app-post для проецирования содержимого.

Для реализации аккордеона:

Внутри компоненты post мы вызываем jsonplaceholder, получаем поддельное сообщение в блоге и показываем его на шаблоне.

Результат:

Первоначальное приложение до ленивой загрузки

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

Реализация ленивой загрузки

Будем использовать @ContentChild из @angular/core, чтобы получить тело аккордеона, применяя синтаксис директивы на <ng-template>. Используем <ng-template>, а не <div>.

Из документации:

<Ng-template> —  это элемент Angular для рендеринга HTML. Он никогда не отображается непосредственно  —  перед рендерингом представления Angular заменяет <ng-template> и его содержимое комментарием. 

Если нет структурной директивы и вы просто заключаете некоторые элементы в <ng-template>, то они исчезают.”

Создадим новую директиву для тела аккордеона:

ng generate directive accordion

Переименуем селектор в [accordion-body]. Цель этой директивы  —  действовать только как селектор для <ng-template>, который содержит тело аккордеона. Единственное изменение, которое мы в нее вносим  —  это переименование.

Теперь добавим директиву [accordion-body] в app-component:

Если вы сейчас перейдете к приложению, то увидите, что компонент app-post вообще не отображается и API не запускается.

Далее приступаем к рефакторингу компоненты app-accordion:

Расширяем уже существующую компоненту аккордеон. Мы применяли @ContentChild для доступа к первому дочернему элементу app-accordion, имеющему AccordionDirective (т. е. [accordion-body]). Обратите внимание, что мы использовали read: TemplateRef, поскольку обращаемся к ссылке на шаблон. О других вариантах в документации.

Теперь применяем это в шаблоне app-accordion:

Обратите внимание на *ngTemplateOutlet, который используется для вставки встроенного представления из подготовленного TemplateRef(accordionBodyRef).

В итоге получаем лениво загруженную компоненту аккордеон и быструю загрузку:

После реализации ленивой загрузки

Жадная загрузка

Данная реализация аккордеона поддерживает только ленивую загрузку. Загрузить “жадно” текущую реализацию мы не можем. Для этого придется создать еще один компонент.

Сделаем существующий компонент аккордеона переиспользуемым, добавив как ленивые, так и жадные возможности загрузки.

Добавим условие *ngIf внутри шаблона аккордеона:

Проверяем, существует ли шаблон accordionBodyRef . Если да, то показываем компонент и содержимое будет загружаться лениво. Если нет, то выбираем accordionBody, используя проекцию контента.

app-component:

Теперь можно применить ту же компоненту app-accordion для отображения содержимого лениво и жадно.

Готовый проект на GitHub.

Читайте также:

Читайте нас в Telegram, VK и Яндекс.Дзен


Перевод статьи Bharath Ravi: Why and How to Lazy Load Components in Angular

Предыдущая статьяВведение в метод Монте-Карло по схеме цепей Маркова
Следующая статьяБыстрое перенаправление в приложение с AutoVerify