Pull to refresh

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

Reading time5 min
Views92K
По мотивам этой трансляции.

Вместо предисловия скажу, что есть такой сайт 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
Comments11

Articles