Статьи

Angular 1 против Angular 2 — Сравнение высокого уровня

Angular 2 в настоящее время все еще находится в Alpha / Developer Preview, но основные функции и основная документация уже доступны . Давайте соберем здесь то, что до сих пор известно о целях проектирования Angular 2 и как они планируются для реализации:

  • Основные цели Angular 2
  • Проще рассуждать о
  • Угловой 1 против Угловой 2 обнаружения изменений
  • Более прозрачные внутренние органы с зонами
  • Улучшены трассировки стека
  • Значительно улучшена производительность (и почему)
  • Улучшенная модульность
  • Улучшенная инъекция зависимости
  • Дружественный веб-компонент (как и почему)
  • Поддержка Shadow DOM
  • Поддержка нативного мобильного рендеринга в Android и iOs
  • Поддержка рендеринга на стороне сервера
  • Улучшенная тестируемость
  • Путь миграции в Angular 2
  • Выводы

Основные цели Angular 2

Основная цель Angular 2 — создать веб-фреймворк, который очень прост в освоении и просто работает. Давайте посмотрим, как это достигается:

Цель: проще рассуждать о

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

  • В Angular 1 не было события завершения цикла дайджеста (см. Причины  нового модуля Forms), потому что такое событие могло вызвать дальнейшие изменения, которые поддерживали цикл дайджеста.
  • мы должны были думать о том, когда звонить $scope.applyили $cope.digest, что не всегда было просто
  • иногда нам приходилось вызывать, $timeoutчтобы Angular завершил цикл дайджеста и выполнял некоторые операции только тогда, когда DOM стабилен

Чтобы облегчить рассуждение об Angular 2, одной из целей было создание более прозрачных внутренних компонентов, которые работают «из коробки».

Для начала давайте посмотрим, как реализован механизм привязки Angular 1 и как он будет сделан более прозрачным.

Как Angular 1 реализует связывание

В Angular 1 ng-modelвозможность редактировать форму и мгновенно отражать эти изменения в JJasascript POJO является одной из основных причин, почему фреймворк стал настолько популярным.

Согласно этому подкасту, это работает в Angular 1 следующим образом  (см. 3:50):

  • во время выполнения Javascript все исправимо по замыслу — мы можем изменить Numberкласс, если нам нужно
  • Angular при запуске исправит все точки асинхронного взаимодействия:

    • таймауты
    • Ajax-запросы
    • события браузера
    • Веб-розетки и т. Д.
  • В этих точках взаимодействия Angular будет выполнять грязную проверку объектов области видимости, чтобы увидеть, произошли ли изменения и, если это так, активировать соответствующих наблюдателей.
  • повторно запустите грязную проверку, чтобы увидеть, произошло ли больше изменений, и повторно запустите наблюдатели и т. д.

Последствия того, как работает связывание в Angular 1

В результате DOM постоянно синхронизирован с POJO, и он просто работает, но иногда все это трудно рассуждать:

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

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

Вводные зоны

Результатом такого рефакторинга является Zone.js , который можно сравнить с эквивалентом локального контекста потока в Java.

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

Как Angular 2 более прозрачен из-за зон

Angular 2 использует механизм зон, чтобы избавиться от многих рассуждений о цикле дайджеста. Этот простой не-Angular специфический код Javascript будет прозрачно запускать дайджест Angular 2, если он запускается компонентом, который находится внутри зоны:

element.addEventListener('keyup', function () {  
  console.log('Key pressed.');
});
});

Больше не нужно $scope.applyили $scope.digestвсе прозрачно работает. Вероятно, в большинстве случаев нам не придется рассуждать о зонах в целом, и все равно будет возможно запускать код за пределами угловой зоны, используя VmTurnZone .

Цель: повышение производительности

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

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

Чтобы лучше понять, как достигается прирост производительности (в 5-10 раз быстрее, чем в Angular 1), лучше обратиться к этому подкасту и  сообщению в блоге . Я постараюсь обобщить две основные причины, по которым Angular 2 намного быстрее:

Быстрая проверка одиночной привязки

Механизм проверки одиночной привязки был оптимизирован, чтобы позволить виртуальной машине Javascript оптимизировать этот код в нативный код путем своевременной компиляции. Вместо рекурсивного сканирования дерева объектов при запуске Angular создается функция, чтобы увидеть, изменилась ли привязка.

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

Избегайте сканирования частей дерева компонентов

Angular 2 позволит разработчику предоставить некоторые гарантии механизму обнаружения изменений, чтобы избежать сканирования частей дерева компонентов. В основном у разработчика будет два варианта:

  • сделайте модель наблюдаемой: Angular обнаружит это и зарегистрирует себя, чтобы наблюдать за моделью. Таким образом, если модель изменится / останется такой же, Angular узнает об этом через наблюдаемый механизм, и поэтому не нужно запускать обнаружение изменений для этого объекта.
  • сделать модель неизменной, используя, например, файл immutable.js от Facebook  . Опять же, идея заключается в том, что Angular обнаружит это и избежит запуска обнаружения изменений на неизменяемых объектах.

Цель: улучшенная модульность

В Angular 1 модули Angular в основном представляют собой контейнеры для инъекций зависимостей, которые группируют связанные функции.

Эти модули, например, не загружаются асинхронно на основе их списков зависимостей при первой необходимости зависимости, как, например, модули AMD.

Угловой 1 и модуль Lazy-loading

Ленивая загрузка в Angular 1 все еще возможна с помощью решения, подобного ocLazyLoad , но в идеале это должно быть что-то родное для фреймворка и более прозрачное, и в соответствии с этим подкастом кажется, что в Angular 2 это будет иметь место (см. В 13:06) ,

Улучшения в npm в качестве менеджера пакетов Frontend

Также в целом команда Angular стремится улучшить npm, чтобы сделать его более дружественным для внешнего интерфейса, не только для Angular, но и для любой библиотеки внешнего интерфейса в целом.

Angular 2 не форсирует это, но если мы решим сделать это, мы сможем воспользоваться новым загрузчиком модулей ES6, который является стандартным асинхронным загрузчиком модулей, который уже может быть использован через pollyfill es6-module-loader  .

Цель: улучшенная инъекция зависимостей

Внедрение зависимостей Angular 1 — это скачок в создании более модульных приложений, но у него есть пара угловых случаев, которые невозможно исправить без серьезных серьезных изменений.

Angular 1 имеет глобальный пул объектов

Один из ключевых моментов DI в Angular 1 состоит в том, что в приложении имеется только один глобальный пул объектов. Это означает, что если, например, основной маршрут загружается, backendServiceи мы переходим к маршруту B, мы можем там лениво загружать другие службы, специфичные для этого маршрута.

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

Angular 1 перезаписывает модули, если они имеют одинаковое имя

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

В Angular 1 есть несколько механизмов DI

В Angular 1 мы можем вводить зависимости в разных местах разными способами:

  • в функции связи по позиции
  • в определении директивы по имени
  • в функции контроллера по имени и т. д.

В Angular 2 есть цель объединить эти механизмы в единый механизм, чтобы уменьшить кривую обучения и улучшить читаемость.

Как Angular 2 DI улучшит ситуацию

В Angular 2 будет только один механизм DI: инжекция конструктора по типу.

    constructor(keyUtils: KeyboardUtils) {
        this.keyUtils = keyUtils;
    }
});

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

Если компонент не имеет определенной зависимости, он делегирует поиск его родительскому инжектору и так далее. Это создает основу для обеспечения собственной поддержки отложенной загрузки в Angular 2.

Цель: дружественный веб-компонент

Будущее сети — это веб-компоненты, и Angular 2 с самого начала хочет хорошо играть с будущими библиотеками веб-компонентов. Для этого одной из целей синтаксиса шаблона Angular 2 является поддержание чистоты атрибутов и не наложение на них каких-либо угловых выражений — все связывается только через свойства.

Чтобы понять, почему это важно, взгляните на этот пример:

<ng1-component>
     <web-component-widget setting="{{angularExpresssion}}"></web-component-widget> 
</ng1-component>

Здесь у нас есть компонент Angular 1, который взаимодействует с будущей библиотекой веб-компонентов.

В чем здесь проблема?

Ну, веб-компонент ведет себя так же, как компонент браузера, например, имеет imgтег.

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

Это на самом деле причина, по которой все подобные атрибуты ng-srcнеобходимы, чтобы обойти эту проблему.

Как Angular 2 будет лучше взаимодействовать с веб-компонентами?

В Angular 2 синтаксис шаблона будет избегать привязки к простым атрибутам, если только не читать константы:

<ng2-component>  
     <web-component-widget [setting]="angularExpresssion"></web-component-widget>
</ng2-component>

[setting]Является свойством связывания , который будет написать значение выражения в свойство компонента. Ни в коем случае не будет угловых выражений в простых атрибутах, чтобы предотвратить проблемы взаимодействия с веб-компонентами.

Поддержка Shadow DOM

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

Веб-компонент по-прежнему может быть реализован в простом HTML / CSS, но изолирован от главной страницы, в некотором смысле аналогично тому, как если бы он был внутри iframe с отдельным корнем документа.

Поскольку Shadow DOM в настоящее время реализован только в Chrome, Angular 2 будет поддерживать его с помощью 3 различных механизмов:

  • режим по умолчанию: по умолчанию Shadow DOM не включен, а внутренние компоненты отображаются в том же дереве документов, что и главная страница
  • эмулируемый Shadow DOM: механизм изоляции CSS Shadow DOM можно объединить с помощью Polymer, добавив CSS внутри компонента с префиксом на лету, чтобы сделать CSS более конкретным
  • истинный Shadow DOM: как уже упоминалось, это работает только в Chrome

Цель: поддержка Native Mobile — iOS и Android

Angular 2 будет иметь два уровня: прикладной уровень и уровень рендеринга. Например, компонент может быть аннотирован различными @Viewаннотациями, которые могут быть включены во время выполнения в зависимости от среды.

Аналогично React Native , Angular 2 позволит поддерживать понятие:

Учись один раз, пиши где угодно

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

Цель: поддержка рендеринга на стороне сервера

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

Это одна из частей Angular 2, которая на данный момент менее ясна, но идея может быть реализована так:

  • происходит запуск и все компоненты связываются
  • но рендеринг не происходит
  • страница отображается на сервере и отправляется по сети
  • Angular проанализирует его и вставит части страницы в DOM, избегая эффекта мерцания

Цель: улучшенная тестируемость

В Angular 2 относительно сложно написать настоящие модульные тесты, потому что, например, ng-modelдействительно требуется тестирование DOM, что приводит к использованию таких решений, как использование PhantomJ .

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

  • они медленно исполняются
  • они хрупкие и их сложнее поддерживать

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

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

Цель: путь миграции в Angular 2

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

Новый маршрутизатор Angular 2 перенесен на Angular 1 и позволит одному и тому же приложению иметь маршруты Angular 1 и Angular 2.

Выводы

Я действительно взволнован Angular 2, после того, как опробовал его с несколькими компонентами, я вижу, как его легче освоить и как прозрачнее для разработчика. Опять же, многие вещи, описанные в этом посте, такие как Zones, просто будут работать.

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

Хотите попробовать?

Это определенно не слишком рано, чтобы попробовать его, если вы хотите попробовать, это  начальный проект , и редактор кода Visual Studio или Webstorm уже предоставляют отличную поддержку Typescript 1.5.