Skip to content

Latest commit

 

History

History
269 lines (204 loc) · 18.2 KB

README-ru-ru.md

File metadata and controls

269 lines (204 loc) · 18.2 KB

#Введение

Цель данного гида — показать набор лучших практик для AngularJS приложений.

Которые были собранны из следующих источников:

  1. Исходный код AngularJS.
  2. Мной прочитанные статьи.
  3. Мой собственный опыт.

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

В этом руководстве вы не найдете общих требований к стилю для разработки на JavaScript. Они есть тут:

  1. Google's JavaScript style guide
  2. Mozilla's JavaScript style guide
  3. GitHub's JavaScript style guide
  4. Douglas Crockford's JavaScript style guide

Для AngularJS разработчиков рекомендуется придерживаться этого гида: Google's JavaScript style guide.

На wiki странице GitHub репозитория AngularJS есть похожая секция созданная ProLoser, вы можете посмотреть ее здесь.

#Содержание

#Общие

Файловая структура

Так как большое AngularJS приложение состоит из множества компонентов оптимальный способ их структурирования — иерархия каталогов.

Есть два основных подхода:

  • В начале разделить по типам компонент, а затем по функциональности:

В таком случае структура каталогов будет выглядеть так:

.
├── app
│   ├── app.js
│   ├── controllers
│   │   ├── page1
│   │   │   ├── FirstCtrl.js
│   │   │   └── SecondCtrl.js
│   │   └── page2
│   │       └── ThirdCtrl.js
│   ├── directives
│   │   ├── page1
│   │   │   └── directive1.js
│   │   └── page2
│   │       ├── directive2.js
│   │       └── directive3.js
│   ├── filters
│   │   ├── page1
│   │   └── page2
│   └── services
│       ├── CommonService.js
│       ├── cache
│       │   ├── Cache1.js
│       │   └── Cache2.js
│       └── models
│           ├── Model1.js
│           └── Model2.js
├── lib
└── test
  • В начале разделить по функциональности, а затем по типам компонентов:

Вот как это выглядит:

.
├── app
│   ├── app.js
│   ├── common
│   │   ├── controllers
│   │   ├── directives
│   │   ├── filters
│   │   └── services
│   ├── page1
│   │   ├── controllers
│   │   │   ├── FirstCtrl.js
│   │   │   └── SecondCtrl.js
│   │   ├── directives
│   │   │   └── directive1.js
│   │   ├── filters
│   │   │   ├── filter1.js
│   │   │   └── filter2.js
│   │   └── services
│   │       ├── service1.js
│   │       └── service2.js
│   └── page2
│       ├── controllers
│       │   └── ThirdCtrl.js
│       ├── directives
│       │   ├── directive2.js
│       │   └── directive3.js
│       ├── filters
│       │   └── filter3.js
│       └── services
│           └── service3.js
├── lib
└── test
  • Когда создается директива, может быть очень удобным положить все связанные с ней файлы в одну директорию (например шаблон, CSS/SASS, JavaScript). Если вы выберите такой подход будьте последовательны и используйте его везде в своем проекте.

      app
      └── directives
          ├── directive1
          │   ├── directive1.html
          │   ├── directive1.js
          │   └── directive1.sass
          └── directive2
              ├── directive2.html
              ├── directive2.js
              └── directive2.sass
    

Этот подход может сочетаться с любым из двух предложенных выше.

  • Еще один способ немного отличающийся от остальных, он используется например в ng-boilerplate. И заключается в том, что unit тесты находятся внутри папки компонента. Это помогает вам, когда вы вносите какие-то изменения в компонент быстро найти его тесты, также при таком подходе, тесты играют роль документации и показывают примеры использования.

      services
      ├── cache
      │   ├── cache1.js
      │   └── cache1.spec.js
      └── models
          ├── model1.js
          └── model1.spec.js
    
  • Файл app.js содержит определения маршрутов, конфигурацию и/или начальную инициализацию (если требуется).

  • Каждый JavaScript файл должен содержать только один компонент. Имя файла должно соответствовать названию компонента.

  • Используйте шаблоны структур AngularJS проектов например такие как Yeoman, ng-boilerplate.

Я предпочитаю первый, потому что в такой структуре проще найти общие компоненты.

Соглашения об именовании компонентов могут быть найдены в соответствующих секциях.

Оптимизация цикла обработки

  • Следите только за жизненно важными переменным (для примера: когда вы используете real-time коммуникации не вызывайте цикл обработки в каждом полученном сообщении).
  • Для контента, который меняется только раз, используйте одноразовые watch, например, bindonce.
  • Сделайте вычисления в $watch максимально простыми. Создание сложных вычислений в $watch замедляет выполнение всего приложения. (цикл $digest работает в одном потоке, потому что JavaScript однопоточный).

Другое

  • Используйте:
    • $timeout вместо setTimeout
    • $window вместо window
    • $document вместо document
    • $http вместо $.ajax

Это сделает ваше тестирование гораздо проще и в некоторых случае убережет от неожиданного поведения (например, если вы забудете $scope.$apply в setTimeout).

  • Автоматизируйте ваши процессы с помощью следующих инструментов:

  • Используйте промисы ($q) взамен callback`ов. Что сделает ваш код более элегантным и чистым и спасет вас от callback hell.

  • Используйте $resource вместо $http где это возможно. Более высокий уровень абстракций убережет вас от избыточного кода.

  • Используйте AngularJS pre-minifier (такой, как ngmin или ng-annotate) для избежания проблем после сжатия скриптов.

  • Не используйте глобальное пространство имен. Разрешайте все зависимости с помощью Dependency Injection.

  • Не захламляйте ваш $scope. Добавляйте только те переменные и функции, который будут использованы в шаблонах.

  • Используйте контроллеры вместо ngInit.

#Модули

Существует два общих способа для структурирования модулей:

  1. По функциональности.
  2. По типу компонента.

На самом деле они не очень то и отличаются, но первый путь выглядит чище. Также если ленивая загрузка модулей будет когда-нибудь реализована (в настоящее время нет в планах AngularJS) — это бы улучшило производительность приложения.

#Контроллеры

  • Не работайте с DOM из контроллеров. Используйте для этого директивы.

  • Именовать контроллеры правильно так, чтобы его имя остояло из части описывающей то чем он занимается (для примера: корзина, домашняя страница, админ панель) и постфикса Ctrl. Имена контроллеров записываются в UpperCamelCase (HomePageCtrl, ShoppingCartCtrl, AdminPanelCtrl, и т.д.).

  • Контроллеры не должны быть объявлены в глобальном пространстве (даже несмотря на то, что AngularJS позволяет сделать это, это плохая практика, которая ведет к его загрязнению).

  • Используйте синтаксис массивов для объявления контроллеров:

      module.controller('MyCtrl', ['dependency1', 'dependency2', ..., 'dependencyn', function (dependency1, dependency2, ..., dependencyn) {
        //...body
      }]);
    

Использование такого типа определения избавляет от проблем с минификицией файлов. Вы можете автоматически сгенерировать определение с синтаксисом массива используя инструмент такой, как ng-annotate (и задачи для grunt grunt-ng-annotate).

  • Используйте оригинальные имена для зависимостей контроллера. Что поможет вам в создании более понятного кода:

      module.controller('MyCtrl', ['$scope', function (s) {
        //...body
      }]);
    

Хуже читается чем:

    module.controller('MyCtrl', ['$scope', function ($scope) {
      //...body
    }]);

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

  • Держите контроллеры настолько маленькими на сколько это возможно. Вынесите общие функции в сервисы.

  • Организовывайте коммуникацию между контроллерами используя вызовы методов (например когда дети хотят связаться с родителями) или $emit, $broadcast и $on методы. Количество $emit, $broadcast сообщений должно быть сведено к минимуму.

  • Сделайте список со всеми сообщениями пересылаемыми с помощью $emit, $broadcast и тщательно следите за ними из-за возможных коллизий имен и других багов.

  • Когда вам нужно отформатировать данные перенесите логику форматирования в фильтр и укажите его как зависимость:

      module.filter('myFormat', function () {
        return function () {
          //body...
        };
      });
    
      module.controller('MyCtrl', ['$scope', 'myFormatFilter', function ($scope, myFormatFilter) {
        //body...
      }]);
    

#Директивы

  • Называйте ваши директивы используя lowerCamelCase.
  • Используйте scope вместо $scope в вашей link функции. В compile, post/pre функциях у вас уже будет предустановленный набор аргументов, которые будут переданы когда функция вызывается, у вас не будет возможности изменить их использую DI. Такой стиль используется и внутри самого AngularJS.
  • Используйте кастомные префиксы для ваших директив во избежании коллизий со сторонними библиотеками.
  • Не используйте префиксы ng или ui, так как они зарезервированы для использования в AngularJS и AngularJS UI.
  • Манипуляции с DOM должны производиться только с помощью директив.
  • Создавайте изолированный scope когда вы разрабатываете переиспользуемые компоненты.

#Фильтры

  • Называйте ваши фильтры используя lowerCamelCase.
  • Сохраняйте ваши фильтры настолько простыми насколько это возможно. Они часто вызываются во время $digest цикла, так что медленный фильтр тормозит все приложение.

#Сервисы

  • Используйте camelCase для имен сервисов.
  • Инкапсулируйте бизнес-логику в сервисы.
  • Инкапусляция бизнес-логики в сервис предпочтительна с использованием service вместо factory.
  • Для кеширования на уровне сессии вы можете использовать $cacheFactory. Она должна использоваться для кеширования результатов запросов или тяжелых вычислений.

#Шаблоны

  • Используйте ng-bind или ng-cloak вместо простого {{ }} для предотвращения мигания контента.

  • Избегайте написания сложного кода в шаблонах.

  • Когда вам нужно установить аттрибут src у картинки динамически, используйте ng-src вместо src внутри содержащего шаблон {{ }}.

  • Вместо использования строковой переменной в scope и использовании ее в атрибуте style через шаблон {{ }}, используйте директиву ng-style с объектом в scope переменной, как значение:

      ...
      $scope.divStyle = {
        width: 200,
        position: 'relative'
      };
      ...
    
      <div ng-style="divStyle">my beautifully styled div which will work in IE</div>;
    

#Маршрутизация

  • Используйте resolve для разрешения зависимостей перед тем, как представление будет показано.