Pull to refresh

Лучшие практики AngularJS

Reading time 5 min
Views 92K
По мотивам этой трансляции.

Вместо предисловия скажу, что есть такой сайт yeoman.io, где собраны наиболее популярные технологии, автоматизирующие разработку фронтенда (сборку, параметризацию CSS и проч.). Обратите на него внимание в начале работы над проектом.

Использование директив


Некоторое количество разработчиков считают, что директивы захламляют HTML, так же им тяжело изменить старые привычки. Стоит заметить, что директивы существуют в HTML с незапамятных времен. Это всем хорошо знакомые элементы формы: поля ввода, радиокнопки, выпадающие списки и проч. Другое дело, что сделаны они «чтобы отстали». Эту проблему и решает Ангуляр.

Сравним обычный чекбокс
<input type="checkbox" name="option1" value="a1" checked>

и чекбокс в Ангуляре
<input type="checkbox" ng-model="myModel">

Что проще? name/id/class можно не указывать, потому что директивы не привязываются по имени. Начальное состояние задается моделью, поэтому checked не имеет смысла. Но это еще не всё. Последний код можно переписать и так
<input type="checkbox"  ng-model="myModel"  ng-true-value="on" ng-false-value="off"  ng-change="change()">

Думаю, многие в начале знакомства с HTML недоумевали почему подобного нет в стандартном варианте, почему чекбокс возвращает on или пустоту, а не true и false, почему можно изменить только значение on и много других почему.

Так вот, Ангуляр просто заставляет вести существующие интерактивные элементы понятным образом, унифицирует связь элементов с данным модели и на этой основе дает возможность создавать какие угодно собственные элементы управления, не дожидаясь прихода HTML5, HTML6 или HTML8.

Теперь рассмотрим директиву, аналогов которой в HTML нет
<ANY ng-repeat="book in books">

На лицо использование логики в тегах. На самом деле это не совсем так. Основная логика, а она гораздо сложнее, упакована в скрипт, описывающий директиву. В атрибут вынесен только интерфейс взаимодействия. Разработчики Ангуляра полагают (и с ними сложно не согласиться), что разметка должна говорить не только о том, КАКИЕ элементы расположены на странице, но так же о том, ЧТО они делают. А описание того КАК они это делают — удел скрипта.

Разумеется, в директиву можно запихать и сложную логику. Можно, вообще, практически любое поведение организовать из набора стандартных директив. Иногда это оправдано, особенно, когда нужно что-то сделать быстро, но Ангуляр не пропагандирует на 100% такой подход.

Все уже знают, что директивы можно записывать несколькими способами
<my-dir></my-dir>
<span my-dir="exp"></span>
<span class="my-dir: exp;"></span>
<!-- directive: my-dir exp -->

Так вот, наиболее предпочтительный (близкий к идеологии) первый способ. В ряде случаев (например, для директив, подобной ng-repeat, или для совместимости, в т.ч. психологической) — второй. Третий сделан просто так. Четвертый необходим, чтобы обойти ограничения HTML, например поместить что-либо отличное от <td> в тег <tr>. Так же для лучшей совместимости со старыми браузерами рекомендуется начинать имя директивы с какого-либо префикса (напр., my-). Для валидаторов можно добавлять к именам префиксы x- или data- (они будут отброшены Ангуляром).

Борьба со вспышками


Другими словами, как сделать загрузку страницы более гладкой для пользователя.

Во-первых, размещайте ангуляровские скрипты в конце страницы, чтобы пользователь не смотрел на белый экран, пока они грузятся.

Во-вторых, обратите внимание на директиву ng-cloak, которая скрывает шаблон до полной его обработки Ангуляром, а так же используйте ng-bind вместо выражения в фигурных скобках {{ }}.

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

Отличие контроллеров от сервисов


Контроллеры описывают поведение вида, т.е. отвечают на вопросы, что произойдет, если нажать на кнопку Х и где проводить работу с данными Х. Для каждого вида приложения создается отдельный экземпляр контроллера. В контроллерах ни в коем случае нельзя проводить манипуляции с DOM. Работа с DOM производится только в директивах.

Сервисы содержат основную логику и отвечают на вопрос что и как делает Х. В отличие от контроллеров, сервисы это синглтоны, т. е. во всем приложении может существовать только один экземпляр сервиса. В них так же не стоит работать с DOM, но иногда можно, например, если необходимо сделать глобальное диалоговое окно и т. п. В любом случае, использование DOM-манипуляций в сервисах необходимо ограничить.

Деградация говнокода


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

Области видимости (scope)


Область видимости связывает вид с контроллером. Она предназначена только для чтения в шаблонах (виде) и только для записи в контроллерах.

Не стоит путать область видимости с моделью. Область видимости это ссылка на модель. Поэтому неправильно записывать параметры модели в область видимости напрямую. Необходимо создать один параметр и поместить туда модель.
//неправильно
$scope.param1 = 'hello';
$scope.param2 = 'world';

//правильно
$scope.model = {
  param1: 'hello',
  param2: 'world'
};

Разница в этих подходах наглядно демонстрируется в этом видео, а так же в первом примере (см. комментарии в коде).

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

Модули


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

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

Производительность


Для ускорения приложений
  • Минифицируйте и объединяйте ява-скрипты
  • Используйте GZIP-сжатие (может ускорить загрузку в два раза)
  • НЕ кэшируйте index.html, т.к. он содержит ссылки на подключаемые библиотеки и браузер, у которого этот файл закэширован, будет всегда ссылаться на их старые версии.
  • Кэшируйте (сохраняя версионность): шаблоны, код, картинки, CSS.

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

Что касается производительности клиентского кода, то она больше всего зависит от двух факторов:
  • Как много данных, требующих связывания, располагается на странице (как правило, они заключаются в {{ }}).
  • Насколько тяжелые выражения вычисляются для этих данных.

Не используйте медленные функции в $watch и в выражениях {{ }}. Так же не имеет значения сколько данных, требующих связывания, на странице, если в данный момент рендерится только один кусок.

Директивы ng-view и ng-include изменяют DOM-структуру приложения, поэтому не попадают в стандартный цикл перерисовки, тогда как ng-show и ng-hide структуру не меняют. С директивой ng-repeat для генерации списков нужно быть осторожнее, т. к., если при сотнях строк всё хорошо, то при тысячах могут начаться тормоза. В этом случае рекомендуется разбивать данные на страницы, использовать поиск и т. п. Можно использовать фильтры, но иногда они могут оказаться слишком дорогими, особенно, когда запускаются снова и снова. В этом случае можно создать вторую, внутреннюю модель. Сохранять в нее отфильтрованные данные из основной модели и уже вторую модель использовать в ng-repeat. Возможны и другие стратегии.

Для вставки шаблонов в DOM предпочтительнее использовать ng-include вместо innerHTML, т. к. она лучше оптимизирована.

Планы на будущее


В данный момент разработчики Ангуляра работают над ленивой загрузкой скриптов, а так же над реализацией пре-рендеринга страницы на сервере, что должно ускорить начальную загрузку, а так же способствовать индексации страницы поисковиками. Так же планируется упростить API директив и доработать анимацию, которая уже появилась в последних версиях фреймворка.
Tags:
Hubs:
+36
Comments 11
Comments Comments 11

Articles