Angular Light — самостоятельная клиентская MV(C/VM) библиотека, которая построена на идеях Angular.js и Knockout.js, и похожа на упрощенный Angular.js



Вышла версия Angular Light 0.11, которая включает много изменений.

В Angular.js, как и в старых версиях Angular Light, Scope — это механизм отслеживания изменений (Change Detector) и в нем располагаются пользовательские данные для отслеживания. Такое смешивание данных и механизма отслеживания в одном объекте породило ряд разных проблем: для таких директив как ng-if/ng-include/ng-repeat фреймворк вынужден создавать дочерние CD с прототипом к родительскому, чтобы иметь доступ к данным — это негативно влияет на расход памяти и скорость работы, но, самое важное, примеры как этот не работают как ожидается:

<div>
    <input type="text" ng-model="value" /> {{value}}
    <div ng-if="flag">
        <input type="text" ng-model="value" /> {{value}}
        <button ng-click="value=5">set</button>
    </div>
</div>


ng-click=«value=5» и ng-model=«value» изменят переменную дочернего CD, которую создал ng-if, а не ту что выше. Из-за этой проблемы авторы Angular.js сделали рекомендации: не использовать данные в корне Scope (используйте имена с «точкой») и использовать controllerAs.
Так же при создании Angular 2, они учли эту проблему — теперь в нем есть отдельный тип ChangeDetector (отдельный от данных).

В Angular Light 0.11 так же внесены изменения в этом плане: бывшый Scope был разделен на ChangeDetector и пользовательские данные, — это дало дополнительную гибкость и подобные примеры (как выше) работают как ожидается:

<div>
    <input type="text" al-value="value"> {{value}}
    <div al-if="flag">        
        <input type="text" al-value="value"> {{value}}
        <button al-click="value=5">set</button>
    </div>
</div>

Пример на jsfiddle

Так же и с al-repeat, al-click=«active=current» внутри цикла меняет пользовательские данные, а не дочерний Scope.
<div>
    {{active.name}}
    <div al-repeat="current in list">
        <div al-click="active=current">{{current.name}}</div>
    </div>
</div>

Пример на jsfiddle

Т.к. al-repeat создает локльные переменные внутри цикла: current, $index, $last и т.п. и они не должны менять пользовательские данные (как и пересекаться с другими циклами), сделан небольшой трюк, а в Angular 2 для этого создана сложная система компиляции (не даром он весит около 1.7 Мб).

Еще одно важное новшество в Angular Light: теперь в нем есть настоящие асинхронные фильтры. Если сравнивать их с Angular.js $stateful фильтрами то можно заметить, что Angular.js вызывает ваш фильтр на каждом $digest цикле, и когда вам нужно «отправить» новое значение вы его возвращаете на следующем $digest цикле, в то время, как Angular Light не «дергает» ваш фильтр каждый раз, вы можете «отправить» новое значение в любой момент (например когда данные пришли с сервера), пример: {{user.companyId | loadCompanyName}}

al-repeat теперь может итерировать по объекту, в отличие от ng-repeat, вы можете задать сортировку.

У дериктив появился «изолированный режим», при правильном использовании это может снизить нагрузку в 100 раз, для тех кто беспокоится о dirty-checking. Так же «замороженные» массивы через Object.freeze дают ускорение dirty-checking и в планах добавление поддержки популярного immutable.js

Ускорен биндинг, теперь Angular Light стал в 2 раза быстрее чем Angular.js (в некоторых случаях), тест, что удивительно — он стал быстрее чем Basis.js, не говоря о других фреймворках.

Не знаю насколько он был нужен, но al-select был добавлен в стандартную поставку, в отличие от ng-options, al-select работает совместно с al-repeat — это дает дополнительную гибкость. Например, в одном select можно использовать несколько al-repeat циклов, или добавлять пользовательские (одиночные) пункты, пример.

alight.bootstrap был немного изменен для более удобного использования, пример:
<div id="app">
    <button al-click="click()">click</button>
    <input type="text" al-value="name" /> Hello {{name}}!
</div>

alight.bootstrap('#app', {
    name: 'user',
    click: function() {
        this.name = 'world'
    }
})

Пример на jsfiddle

Также внесено несколько меннее значимых улучшений. Для тех кто использовал Angular Light 0.10 и старше, есть список основных отличий.

Предыдущие статьи:

Комментарии (22)


  1. Evgeny42
    29.11.2015 22:31

    CSP то запилили? :)


    1. lega
      29.11.2015 22:49

      На данный момент можно подключить notevil.js, пример, а для максимальной скорости можно сохранить кеш функций для приложения (но это ручная работа). Если включить notevil в состав AL, то он потяжелеет в 2 раза, если не больше, при том что CSP нужен не всем.


      1. Evgeny42
        29.11.2015 23:04

        Да, это же я вас надоумил попробовать прицепить CSP, пол года назад вроде. Я даже переписал приложение полностью на al, но производительность меня не удовлетворила.


        1. lega
          30.11.2015 00:33

          Почти любые «тормоза» можно оптимизировать, нужно разбираться. Есть где посмотреть ваше приложение?


          1. Evgeny42
            30.11.2015 02:41

            Скорее всего это было связано с notevil.js и тем что firefox os не понимает observe. Что очень и очень грустно.


  1. novoxudonoser
    29.11.2015 23:44
    +1

    Есть где почитать список того что нет в al по сравнению с прародителем?


    1. PerlPower
      30.11.2015 00:40
      +19

      Вакансий.


    1. lega
      30.11.2015 01:21

      Нет модулей, констант, значений, фабрик, сервисов, провайдеров, DI, можно использовать готовые аналоги, requirejs или т.п. А если AL подключать в готовый проект, то там наверняка уже что-то используется.
      Нет роутера, можно использовать один из jQuery реализация, либо сделать свой (в 30 строк), пример.

      Есть асинхронные фильтры, текстовые директивы и ещё разные «плюшки», но самое главное Angular Light — библиотека, по отзывам разработчиков, с AL разработка проще и удобней.

      Вакансий.
      Да, это с любой малоизвестной технологией.


      1. k12th
        30.11.2015 11:31

        Без DI все-таки грустно. Константы-модули-значения — в биореактор, нефиг бизнес-логику писать в терминах фреймворка. Но без DI получается чуть больше чем тот же knockout/ractive/rivets?


        1. RouR
          30.11.2015 13:49

          В статье есть ссылка не тесты, получается по шустрее чем те же knockout/ractive/rivets.
          Если приложение не SPA, то вполне норм.


          1. k12th
            30.11.2015 13:53

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


        1. lega
          30.11.2015 14:50

          DI можно прикрутить, кому нужно, хотя чем это лучше например такого?: myService = require('myService') который можно вызывать из любого места.
          Knockout и Ractive используют observable подход (первый точно), второй через set/get. Rivets, на сколько я понял, тоже observable, но через Object.defineProperties.

          Angular Light использует dirty-checking (как и Angular.js), отсюда свои плюсы и минусы, например dirty-checking не делает тяжелую обвязку (observe) вокруг данных, что дает хорошую производительность (вопреки многим мнениям). С dirty-checking вы работаете с обычными типами строки, объекты, когда в knckockout.js вам нужно заворачивать/разворачивать данные в observable объекты.

          Незнаю на счет ractive/rivets, но Angular Light хорошо расширяем, например можно наследовать директивы, динамический загружать директивы, расширять систему обработки директив, есть namespaces для директив и фильтров, текстовые директивы (где ещё они есть?), можно даже сделать биндинг в стиле Ember.jsпример, и др. мелкие фичи.

          Angular Light хорош для встраивания, например если ваш виджет должны размещать на других сайтах без последствий, если вы сделаете такой виджет на Angular2 то он подменить глобальные setTimeout, setInterval, requestAnimationFrame и т.п. — и чужой сайт, какой фреймворк бы там не был, будет работать через подключенный Angular 2 :(


          1. k12th
            30.11.2015 14:58

            DI можно прикрутить, кому нужно, хотя чем это лучше например такого?: myService = require('myService') который можно вызывать из любого места.

            require('myService') — это не DI, даже отдаленно (хотя модульная система вообще это must have). Строго говоря, это перпендикулярные друг другу вещи. Я-то могу прикрутить DI, а джуниор в соседнем кубикле?

            Rivets, на сколько я понял, тоже observable, но через Object.defineProperties.
            Не знаю, что это такое, но да, через Object.defineProperties.

            Окей, я вас понял, спасибо за информацию.


            1. lega
              30.11.2015 15:27

              Я-то могу прикрутить DI, а джуниор в соседнем кубикле?
              Джуниору вообще DI не нужен, имхо, DI нужен тем кто уже созрел для него, кто понимает плюсы, а некоторым он вообще не нравится. А Angular.js пытается вывалить все свои фичи (DI, фабрики, провайдеры...) на новичков — это повышает порог входа, а я за плавное изучение новых фич.

              require('myService') — это не DI, даже отдаленно
              Да, но вопрос не в этом, вот и вот как requirejs можно использовать и таких обсуждений много, даже есть готовые легковесные решения. Вообщем кому надо, могут использовать готовое.


              1. k12th
                30.11.2015 15:51
                +1

                а некоторым он вообще не нравится
                такой, как в ангуляре, мне тоже не нравится:)

                По первой ссылке чувак слабо знаком с предметом — я тоже думал, что requireJS это про DI «even if not in the most purist sense of the term» — до того, как написал первое приложение:) По второй чувак слышал звон, но не знает, где он. В первом ответе как раз раскрывается, что такое DI. Вообще, конечно, загрузка модулей может служить частью имплементации, но вообще-то этому паттерну все равно, как именно классы/инстансы попадают в область видимости.

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


            1. lega
              30.11.2015 15:34
              +1

              Я, наверно, сделаю DI внешним пакетом. Некоторые «расширения» накапливаются, которые могут быть полезны другим.


        1. lega
          30.11.2015 17:01

          Сделал пример, как бы мог выглядеть DI в AL, зависимость указал через атрибут «inject», сервис добавил через requirejs.


          1. k12th
            30.11.2015 17:10

            Спасибо, но это не совсем то.

            Загружу файл я сам (в 2015-то году можно уже ES2015-модули использовать, спасибо SystemJS), а вот создать инстанс класса с нужными параметрами, зарезолвив, в свою очередь, его зависимости — вот этого не хватает:(
            Впрочем, для микробиблиотеки, возможно, в самый раз.


            1. lega
              30.11.2015 17:22
              +1

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


              1. k12th
                30.11.2015 17:24
                +1

                Вы никак не хотите понять, что модули и DI — это разные вещи. Я уж не знаю, как вам это выразить.

                Ангуляр в свое время крепко поднагадил всем в мозги своими «модулями»:(


  1. artemenko
    30.11.2015 12:36
    +4

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


    1. baka_cirno
      30.11.2015 16:01

      Те же впечатления. Vue.js — это Angular 1.х (точнее, его ViewModel часть), изначально сделанный правильно.