Ключевое отличие AngularJS от Knockout

    imageЗа последнее время я несколько раз успел поучаствовать в дискуссиях о том, чем Angular лучше или хуже Knockout и других JS-фреймворков. И очень часто я сталкивался с тем, что есть некоторое непонимание сути различий в подходах, заложенных в эти продукты. Иногда дело доходило даже до того, что в качестве преимущества Knockout приводились валидные по умолчанию префиксы «data-», что ну просто совсем смешно (не говоря уж о том, что их можно использовать и в Angular).

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

    1. Модульная организация кода, тестируемость и жестокая война с любыми глобальными данными.
    2. Пропаганда декларативного подхода через создание собственных HTML-директив.
    3. Механизм проверки изменения данных в дата-биндинге без использования коллбэков.

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

    Что такое дата-биндинг? Грубо говоря, это отображение данных в шаблоне, выполненное так, чтобы изменение данных изменяло их представление. Имея объект:
    var myViewModel = {
        personName: 'Bob',
        personAge: 123
    };
    
    … и шаблон:
    <span>personName</span>
    

    … мы хотим, чтобы span при изменении myViewModel обновлялся до актуального состояния с минимальным нашим участием. И наоборот, если это, например, поле ввода.

    И для решения этой задачи есть два принципиально различных подхода.

    Change listeners

    Для механизма дата-биндинга в таких фреймворках как Knockout и Backbone была разработана система отслеживания изменений (change listeners). Вы работаете с данными не напрямую, а через специальный слой (например, observables в KO), призванный вовремя менять представление данных при их изменении. Любая переменная превращается в объект фреймворка, который следит за состоянием.

    var myViewModel = {
        personName: ko.observable('Bob'),
        personAge: ko.observable(123)
    };
    ...
    myViewModel.personName('Mary');
    myViewModel.personAge(50);
    

    <span data-bind="text: personName"></span>
    


    Умное и очевидное решение. Казалось бы, функциональное и событийно-ориентированное программирование в javascript подходит как нельзя лучше для подобных задач, да и вообще работа с коллбэками — наш сильный конек.

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

    Во-первых, что, если одна часть данных каким-то способом зависит от другой части? Изменив одну переменную, мы автоматически сообщаем об этом, но изменившаяся при этом вторая переменная останется незамеченной. Для разрешения подобных зависимостей в KO существует механизм dependency tracking, который работает хорошо, но само наличие решения говорит о существовании проблемы.

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

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

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

    Dirty checking

    По этому принципу работает AngularJS. Dirty checking — это проверка на изменененность данных, простая как два рубля. Раньше переменная myVar была 1, теперь она 2 — значит данные изменились и надо их в шаблоне перерисовать. Для простых переменных это оператор !=, для сложных — соответствующие легковесные процедуры. Это простейший подход, который избавляет нас как от необходимости работать с данными через специальный «слушающий» слой, так и от всех проблем, связанных с зависимостями данных.

    var myViewModel = {
        personName: 'Bob',
        personAge: 123
    };
    ...
    myViewModel.personName = 'Mary';
    myViewModel.personAge = 50;
    

    <span>{{personName}}</span>
    


    Весь вопрос в том, когда производить эту проверку? Непрерывно, по таймеру? Учитывая, что модель данных может быть довольно сложной, то непрерывно производящиеся проверки могут сильно ухудшить UX. В Angular этот вопрос решается путем автоматического вызова функции $digest после каждого участка кода, предположительно могущего изменить данные. Это ключевой момент — проверка выполняется тогда и только тогда, когда данные могли быть изменены (например, при действии пользователя), и никогда не выполняется в других случаях. Если вы ожидаете изменения данных в какой-то другой момент времени (например, при поступлении события от сервера или завершении какого-либо процесса), вы должны явно указать Angular, что стоит выполнить проверку, вызвав функцию $apply.

    При этом данные на каждой итерации проверяются все сразу, целиком, а не лишь какая-то часть. До и после окончания выполнения $digest мы имеем стабильную версию всего состояния без рассинхронизаций. Если из-за зависимостей данных какая-то одна их часть в процессе проверки изменилась, то сразу после окончания текущей проверки будет запланировано выполнение следующей. И следующая проверка снова выполнится целиком, обновляя состояние модели полностью, ликвидируя возможные проблемы с неучтенными зависимостями.

    Очевидный минус этого подхода — производительность. Хотя и здесь есть небольшое исключение: например, при пакетном обновлении сразу большого количества данных проверка выполняется всего один раз в конце, а не при каждом изменении каждого из отслеживаемых объектов, как это происходит в первом случае. Но в целом, это тем не менее минус, так как при изменении всего одной переменной выполняется dirty check всех данных.

    Нужно лишь понять, насколько сильны потери производительности.

    Тут стоит отметить, что Angular во время выполнении dirty check никогда не работает с DOM. Все данные — это нативные объекты js, с которыми все современные движки браузеров молниеносно выполняют большинство основных операций. Хотя вы и можете сами вставлять процедуры проверки в процесс dirty check, документация Angular настоятельно рекомендует не работать с DOM внутри них, так как это может сильно замедлить весь процесс.

    Учитывая это, можно сказать, что потеря производительности в сегодняшних условиях работы веб-приложений на практике не ощущается. Раньше я немалое время занимался разработкой игр под мобильные платформы, и там (особенно на старых вроде Palm OS) на счету обычно был каждый лишний такт процессора. Но даже при такой нехватке ресурсов основным принципом работы «дата-биндинга» был именно простейший dirty check. Что такое дата-биндинг в случае игры? Это отображение картинок на игровом экране в зависимости от того, что происходит в состоянии данных игры. Иногда, действительно, использовался подход, близкий к подходу слушающих коллбэков — например, обновление экрана только лишь в тех местах, где картинка поменялась. Но в основном экран просто перерисовался каждый раз заново целиком, замещая текущий кадр новым актуальным состоянием графики. И единственным критерием правомерности такого подхода был и остается показатель FPS — как часто мы можем менять таким образом кадры и насколько плавным будет соответствующий UX. До тех пор, пока FPS находится в районе максимально возможного для восприятия человеком (в районе 30 кадров в секунду), о потерях быстродействия просто нет смысла думать, так как они не приводят ни к чему, что можно назвать ухудшением UX.

    Факт заключается в том, что простой dirty checking, применяемый в AngularJS, позволяет работать с данными практически любой сложности, и при этом выполнять проверку и менять отображение менее, чем за 50мс, а это хоть и дольше, чем если бы мы проверяли лишь часть данных, но тем не менее мгновенно для пользователя. И при этом такой подход избавляет от множества различных головных болей, вызываемых сложным механизмом change listeners, да и просто упрощает работу, ведь мы продолжаем обращаться с данными как с обычными переменными и POJO-объектами, не задействуя сложный синтаксис «слушающего» слоя.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 64
    • 0
      То есть при изменении поля ввода пользователем нам его onchage (в лучшем случае) нужно вешать $digest?

      А вообще очень не хватает какого-то примера кода.
      • +3
        В Angular не надо, надо просто связать это поле с переменной типа:
        <input type="text" ng-model="somevar.somefield"/>

        За это, честно говоря, Angular мне очень нравится.
        • 0
          Просто, честно говоря, первый раз про Angular слышу, может попадался где, но даже в памяти не отложился.
          • +1
            Примеров кода достаточно прямо на главной angularjs.org
      • +9
        Годная статья, спасибо.

        Касательно производительности — в ближайшее время это не будет вообще вызывать вопросов, потому что в новых спецификациях Ecmascript появился Object.observe. У команды AngularJS уже в планах замена (при условии поддержки браузером, конечно) dirty check на использование Object.observe().
        • 0
          А разве у них не появятся сразу проблемы с dependency tracking?
          • +1
            Я не вдавался в подробности, но главный разработчик фреймворка имеет в своем форке ветку github.com/mhevery/angular.js/tree/ObjectObserve. Значит вопрос решаемый.
            • +1
              Не появится, потому что проблемы dependency tracking не в обзёрверах, а в том как их готовить.
          • 0
            На тему databinding в AngularJS есть еще вот такой ответ на StackOverflow. В прицнипе там говорится про то же. что и в статье.
            • 0
              Да, я где-то это читал, и никак не мог потом найти чей это был блог. Оказывается, не блог, а StackOverflow.
            • 0
              Спасибо за статью! Knockout и Backbone не очень подходят для больших проектов с кучей pojo и биндингами, а тут кажется дела получше будут.
              • НЛО прилетело и опубликовало эту надпись здесь
                • +1
                  Да, throttling похож на то, что используется в Angular. Загвоздка лишь в том, что его надо явно каждый раз указывать, он усложняет синтаксис, и при повсеместном его указании (а именно так бы делал я, используя Knockout, по причинам, описанным в статье) мы получаем жутко навороченный код, который при этом функционирует аналогично простому и прозрачному механизму в Angular.
                  • НЛО прилетело и опубликовало эту надпись здесь
                    • +1
                      Чем в контексте индексации поисковиками Knockout отличается от Angular?
                      • НЛО прилетело и опубликовало эту надпись здесь
                        • +5
                          Посмотрите главную страницу angularjs.org — все примеры, которые там показаны, работают как точечное использование Angular лишь в каком-то одном локальном месте на странице со своим собственным маленьким контроллером. При этом контроллеров на одной странице работает несколько штук параллельно, а в целом страница статична.

                          Именно в отношении модульности кода и представления Angular на голову выше Knockout, о чем я написал в начале статьи первым пунктом. Удивительно, что вы ставите этот момент в преимущество Knockout.

                          Цитата с главной:
                          AngularJS works great with other technologies. Add as much or as little of AngularJS to an existing page as you like. Many other frameworks require full commitment. This page has multiple AngularJS applications embedded in it. Because AngularJS has no global state multiple apps can run on a single page without the use of iframes. We encourage you to view-source and look around.
                          • НЛО прилетело и опубликовало эту надпись здесь
                            • +2
                              Прошу прощения, но я снова повторю вопрос: в чем Knockout лучше индексируется, чем Angular? Любой механизм дата-биндинга вызывает одинаковые проблемы с индексацией, вне зависимости от принципа его работы.
                              • НЛО прилетело и опубликовало эту надпись здесь
                                • +6
                                  Вы просто недостаточно изучили Angular, в частности там есть директива ngBind для этого.

                                  Вместо:

                                  <span>{{variableValue}}</span>
                                  

                                  можно использовать синтаксис:

                                  <span ng-bind="variableValue">static indexed value</span>
                                  
                                  • НЛО прилетело и опубликовало эту надпись здесь
                                    • +2
                                      Покажите, что вы хотите видеть и как вы это делаете в KO, и я покажу аналогичную запись в Angular.
                                      • 0
                                        <ul ng-include="'your/dynamic/list'">
                                            <li>seo-friendly item1</li>
                                            <li>seo-friendly item2</li>
                                        </ul>
                                        
                                        <script type="text/ng-template" id="your/dynamic/list">
                                            <li ng-repeat="item in items" ng-bind="item.name"></li>
                                        </script>
                                        
                                        
                                    • 0
                                      Можете поделиться опытом успешного создания (хоть какого-то) гибрида под KO, не переписывая весь процесс рендеринга на серверной части?

                                      Я рыл, много рыл в этом направлении. Но кроме недоделок — портирования KO под nodejs — ничего дельного не нашёл.
                      • +2
                        вот про индексацию поисковиками — www.yearofmoo.com/2012/11/angularjs-and-seo.html
                        к тому же необязательно делать одностраничное приложение, можно встраивать в сайт (хотя придется использовать хаки типа init для инициализации начальными значениями с сервера)
                        • НЛО прилетело и опубликовало эту надпись здесь
                          • +1
                            > если вы готовы полностью неа него проект переводить, и вам не нужна индексация поисковиками
                            > Известное решение. Но очень тормозное.

                            хмм. т.е. решение как бы есть. не сверхъестественной сложности.
                            да и все, что пишется на js, все равно тяжело поисковиками обрабатывается.
                            поэтому для блога, к примеру, не имеет смысла отрисовывать сам текст поста на javascript, но создание нового или редактирование, да и любая «админка» отлично ложится на angular
                        • +3
                          Активно использую Angular на работе и в личных проектах. Однако параллельно слежу за derbyjs. Там, как раз, с индексацией полный порядок. Его код выполняется как на сервере так и в браузере.
                          • 0
                            И что вы можете про него сказать интересного? Что вам мешает начать его использовать?
                            • +2
                              Интересное в нем то, что он ориентирован на многопользовательский класс приложений реального времени — все взаимодействие с бэкэндом происходит через socket.io. Шаблоны у него могут обрабатываться как на сервере так и на клиенте. Т.е. если запрос через ajax — отправляются чистые данные, если пользователь только что перешел по URL то все это рендерится на сервере и выдается готовая страница. Это решает проблему индексации поисковиками.
                              По идеологии похож на meteorjs, о котором последнее время столько шума. Но он поддерживает npm, а это большой плюс (для меня по крайней мере).
                              Использовать пока желания нет особого по той простой причине что он еще не production ready и многое может измениться. Однако за кодовой базой следить интересно.
                              • +2
                                Один из создателей фрейморка раньше работал как PM в команде Google Search, поэтому они активно делают упор на двойной рендеринг. Рекомендую почитать их видение в блоге blog.derbyjs.com.
                                • +1
                                  Спасибо, взял на заметку.
                            • +1
                              Там можно использовать синтаксис #! который поддерживается как yandex так и google.
                            • +3
                              > Если мы изменяем данные непрерывно или большими порциями сразу, то это вызовет очень много ненужных срабатываний, ведь конечная цель — всего лишь изменить отображение, которые так или иначе будет приведено к итоговому виду, и промежуточные состояния тут не нужны.

                              Тут дело в том, что нужно менять observable, отвечающий за соответствующее отображение только тогда, когда вам нужно поменять отображение. Если ваше приложение меняет данные отображения во время какой-то своей внутренней работы, то это значит, что с архитектурой что-то не то: например, вы просто пожадничали ещё один observable.
                              • +1
                                Часто из того места, где меняется модель, я не могу знать, когда нужно менять отображение, а когда нет. Например, есть массив чисел, который отображается путем суммирования всех его элементов. Я могу менять элементы как по отдельности, так и все вместе в цикле, загружая новый массив. И если в первом случае можно перерисовывать отображение каждый раз, то во втором случае отображение суммы достаточно изменить один раз в конце цикла. Сам код изменения одного элемента массива может не знать о том, меняет ли он один элемент и всё, или же работает внутри какого-то цикла.

                                Да, вы правы, можно дать ему знать об этом созданием дополнительного слоя, но, во-первых, это усложнение архитектуры (часто уходя в сторону от разделения модели и контроллера), а во-вторых, это то, о чем написано в статье:

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

                                Работа Angular в этом отношении значительно проще и оставляет меньше места для проблем.
                                • +1
                                  Реализация «события обновления» для такой структуры как массив — вообще вещь не очень очевидная, и для каждого фреймворка сугубо своя. В остальном же, я считаю, что, разрабатывая на каком-то фреймворке, нужно знать, как устроен механизм взаимодействия между разными его компонентами — это основа оптимизированного кода: не важно, knockoutjs у вас под рукой или angularjs.

                                  К слову о дополнительных слоях. Да, действительно, это слишком усложняет. Но простой принцип «сначала сделай всё, а потом — отобрази» (не говорю о долгих операциях) обычно работает на ура.
                                  • +1
                                    Дело в том, что в AngularJS вообще нет «событий обновления массива» в данном случае. Есть «событие обновления суммы элементов массива», и проверка на срабатывание этого события происходит постоянно при каждой итерации dirty check, вне зависимости от того, считаем ли мы сам массив измененным или нет. Например, массив мог остаться прежним, а изменился метод подсчета суммы, и будет срабатывание dirty check, так как хотя модель осталась прежней, но её представление изменилось.
                                    • +1
                                      Я вам вполне верю, что для некоторых задач Angular лучше, и нигде с этим не спорю :)

                                      Я не очень могу понять «Часто из того места, где меняется модель, я не могу знать, когда нужно менять отображение, а когда нет» и говорю о том, что это знание следует из применяемого фреймворка только и той архитектуры, которая накручена на всё это.
                                      • +1
                                        Да. Другими словами, фреймворк, обязывающий иметь подобное знание, не позволяет сделать по-настоящему полное разделение модели и логики работы с моделью. То есть моя позиция заключается в том, что дата-биндинг в варианте KO неизбежно ухудшает архитектуру приложения, в отличие от Angular, дата-биндинг которого дает полную свободу действий в этом плане. Единственный минус этого — производительность, а в остальном сплошные плюсы.

                              • 0
                                В дополнение, в руководстве разработчика есть еще неплохое описание, как оно там все в AngularJS работает: Conceptual Overview.
                                • 0
                                  Спасибо за статью. С angular вроде все ясно. По тику пересчитывается все и готово. А вот как в ko работают dependent observables, до сих пор загадка. Они там умные, к примеру
                                  this.computed = ko.computed(function() {
                                  if (this.var1()) return this.var2();
                                  return 0;
                                  },this);
                                  — в этом коде, если this.var1() == false, computed выражение не будет пересчитываться при изменении var2(). У вас есть идеи, как dependency tracking работает, в чем идея?
                                  • +1
                                    Так спрашиваете, как будто исходники закрыты :)

                                    Там суть в следующем: все observables при инициализации выполняются (можете проверить это, добавив в них console.log, например), таким образом строится дерево зависимостей.

                                    Это же свойство позволяет нам полезно модифицировать KnockoutJS так, чтобы сделать загрузку observables «ленивой»: сделать её таким образом, чтобы инициализация происходила не в момент инициализации вью-модели, а в момент первого обращения программиста к самой observable или к observable, от неё зависимой.
                                    • 0
                                      Только при обращении к самой observable, видимо? Потому как пока она не вызвана, не построено дерево, и мы не знаем, от чего она зависит.

                                      Иногда бывает, что какая-нибудь конструкция никак в голове не уложится. Т.е. есть дерево зависимостей, по нему быстро определяется, какие computed нужно пересчитать при изменении observable. А сам computed — это что-то такое:
                                      ko.computed = function(callback) {
                                      var IAmInComputedObservable = true;
                                      var computedObservableUniqId = ...;
                                      callback();
                                      }
                                      И вызывается код, который в computed-переменной. Последний обращается к какой-нибудь observable, а та видит переменную IAmInComputedObservable, и это значит, что ей нужно достроить дерево зависимостей из нее на compuedObservableUniqId. И почистить которых нет. Такой смысл?
                                    • 0
                                      При объявлении computed, KO запускает его, и другие observable увеличивают некий счётчик типа var1_ref_count. По завершению работы computed, КО смотрит, какие счетчики увеличились и «подписывает» computed на соответствующие observables
                                      • 0
                                        И если не var2 не будет вычислена, то свой счетчик она не увеличит, и КО не подпишет комптютед на нее.
                                        Решается это так: в начале компьютеда считываете нужные обсёрвеблс в переменные и работаете с ними:
                                        this.computed = ko.computed(function() {
                                        var var1 = this.var1();
                                        var var2 = this.var2();
                                        if (var1) return var2;
                                        return 0;
                                        },this);
                                        • НЛО прилетело и опубликовало эту надпись здесь
                                    • +1
                                      Хочу обратить внимание, что эти два подхода слежения за изменениями--это по сути разновидности Pull и Push парадигм работы с данными (так же как и классический http/web-sockets).
                                      • 0
                                        Это больше похоже на паттерны.
                                      • 0
                                        Спасибо за статью, я как раз не могу решить что выбрать. Не подскажите какой подход для привязки данных реализован в ember.js?
                                        • 0
                                          50мс — это очень дофига, если у анс идёт пересчёт при скроллинге, например, или при движении мыши
                                          • 0
                                            Попробуйте вывести грид на 20 колонок и 1000 строк биндингом в ангуляре.
                                            Задержка будет порядка 500мс на core i5, ddr3.
                                            В случае knockout ничего такого не будет.
                                            • +1
                                              Во-первых, этому посту полтора года.

                                              Во-вторых, эту тему уже так часто перетирали в интернетах, что отвечать по пятнадцатому разу не имеет смысла. Просто погуглите, как на ангуляре правильно работать со scope, и чем View-Model отличается от Model в парадигме MVVM. Не бывает задачи сделать 20х1000 живых индивидуальных биндингов на одном пользовательском view, умещающемся в экран. Либо на текущем экране их будет меньше, либо биндинги будут не индивидуальные.

                                              А в-третьих, вот.
                                              • 0
                                                Не так то это просто. Это как пример тормозов ангуляра, не всегда модель дайджеста хорошо используется.
                                                По вашей ссылке ещё не реализованная фича (бета).
                                                • 0
                                                  Если молоток использовать неправильно, им тоже можно пальцы отбить.

                                                  По вашей ссылке ещё не реализованная фича (бета).
                                                  Фича реализованная и законченная, я активно ей пользуюсь в текущем проекте. Бета — это статус сборки, а не конкретных фич. Зная динамику развития ангуляра, могу предположить, что 1.3 выйдет в stable в течение месяца-двух. Но в любом случае, вот еще вариант импровизации на тему: github.com/Pasvaz/bindonce
                                                  • 0
                                                    Если клавиатуру использовать неправильно можно и пальцы погнуть.
                                                    Бета версию использовать в продукте не считаю правильным.
                                                    Производительность хваленого в статье биндинга ангуляра от этого быстрее не становится.
                                                    • +2
                                                      Демагогия какая-то. Речь о том, что вы просто хуже знаете ангуляр, чем нокаут, и вместо того, чтобы почитать о приемах работы с ангуляром (в частности, как писать код так, чтобы ваши проблемы с производительностью вообще не возникали), вы играете словами и придираетесь к незначимым временным явлениям вроде статуса текущей сборки, которая будет неактуальна уже через месяц. Тут, извините, проблема не ангуляра, а лично ваша. Любую технологию можно заставить тормозить, если специально задаться этой целью.
                                                      • 0
                                                        Согласен. Но в статье нет ни слова о такой ситуации. Все просто гладко и идеально. Заказуха какая-то.
                                                        Я вам просто привел пример, когда ангуляр будет медленее работать со своей системой биндинга, чем knockout с событийной системой.
                                                        • 0
                                                          Странно. Цитата из статьи:
                                                          Очевидный минус этого подхода — производительность. Хотя и здесь есть небольшое исключение: например, при пакетном обновлении сразу большого количества данных проверка выполняется всего один раз в конце, а не при каждом изменении каждого из отслеживаемых объектов, как это происходит в первом случае. Но в целом, это тем не менее минус, так как при изменении всего одной переменной выполняется dirty check всех данных.

                                                          Нужно лишь понять, насколько сильны потери производительности.
                                                        • 0
                                                          Эти «приёмы» правильнее всё же называть «костылями». Агнуляр умудряется тормозить и требовать применения «приёмов» там, где более толковые решения даже не затыкаются. Рендерить только видимые ячейки хорошо, когда они все одного размера и представляют из себя плоский список. Но стоит им начать подстраиваться под размер содержимого, динамически меняться в размерах и представлять из себя иерархическую структуру, так сразу определение что видимо, а что нет становится весьма нетривиальной задачей.

                                                          И да, в более других решениях биндинги ничего не стоят (не считая небольшого потребления памяти) и их не надо отключать, лишая себя автоматической актуализации вьюшки.
                                                          • 0
                                                            Агнуляр умудряется тормозить и требовать применения «приёмов» там, где более толковые решения даже не затыкаются.

                                                            Применение «приемов» требует любой инструмент, начиная с молотка и напильника, которые надо держать под нужным углом, что тоже является приемом. Причем ангуляр требует на порядок меньшего объема приемов. Ведь в ангуляре специально думать о биндингах нужно начинать только тогда, когда их количество становится критичным для скорости работы (чтобы бывает довольно редко), а в нокауте о биндингах надо думать всё время, явно задавая и связывая цепочки observables (т.е. применяя приемы работы с технологией) по сто раз в день во время разработки. И вспоминать, где и чего забыл указать, когда что-то не заработало.

                                                            И я никак не могу понять, какая же злая сила заставляет делать 20х1000 индивидуальных биндингов, почему нельзя сделать их одним сложным биндингом? kinguru специально взял нереальный пример, чтобы продемонстрировать якобы реальный недостаток технологии.
                                                            • 0
                                                              Пример кстати вполне реальный :)
                                                              К примеру, страница печати отчета.
                                                  • 0
                                                    Простите, что снова реинкарнирую пост, но все же…
                                                    Что Вы подразумеваете под «индивидуальные биндинги» и «одним сложным биндингом». Правильно ли я понимаю, что под первыми имелось ввиду привязка каждой отдельной записи (не через ngRepeate), а под вторыми, скорее всего, — своя реализация виртуализации?
                                                • 0
                                                  Не совсем понятно, как можно попасть в knockout на середину трекинга депов, если javascript работает в одном потоке.

                                                  Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.