Как работает привязка данных в AngularJS
рамках?
Я не нашел технических деталей на их сайте . Более или менее понятно, как это работает, когда данные распространяются от вида к модели. Но как AngularJS отслеживает изменения свойств модели без сеттеров и геттеров?
Я обнаружил, что есть наблюдатели JavaScript, которые могут выполнять эту работу. Но они не поддерживаются в Internet Explorer 6 и Internet Explorer 7 . Так как же AngularJS узнает, что я изменил, например, следующее и отразил это изменение в виде?
myobject.myproperty="new value";
javascript
angularjs
data-binding
Pashec
источник
источник
Ответы:
AngularJS запоминает значение и сравнивает его с предыдущим значением. Это основная грязная проверка. Если есть изменение в значении, то это вызывает событие изменения.
Вызывается
$apply()
метод, который вы называете, когда переходите из мира, отличного от AngularJS, в мир AngularJS$digest()
. Дайджест - это просто старая грязная проверка. Он работает во всех браузерах и полностью предсказуем.В отличие от грязной проверки (AngularJS) и слушателей изменений ( KnockoutJS и Backbone.js ): хотя грязная проверка может показаться простой и даже неэффективной (я расскажу об этом позже), оказывается, что она семантически верна все время, в то время как слушатели изменений имеют много странных угловых случаев и нуждаются в таких вещах, как отслеживание зависимостей, чтобы сделать его более семантически правильным. Отслеживание зависимостей KnockoutJS - это умная функция для проблемы, которой нет у AngularJS.
Проблемы со сменой слушателей:
Как насчет производительности?
Так что может показаться, что мы медлительны, поскольку грязная проверка неэффективна. Здесь мы должны смотреть на реальные числа, а не просто иметь теоретические аргументы, но сначала давайте определим некоторые ограничения.
Люди это:
Медленно - все, что быстрее 50 мс, незаметно для человека и поэтому может рассматриваться как «мгновенное».
Ограниченный - Вы не можете действительно показать больше чем приблизительно 2000 частей информации человеку на одной странице. Что-то большее, чем это, действительно плохой пользовательский интерфейс, и люди все равно не смогут это обработать.
Таким образом, реальный вопрос заключается в следующем: сколько сравнений вы можете сделать в браузере за 50 мс? На этот вопрос сложно ответить, так как в игру вступают многие факторы, но вот контрольный пример: http://jsperf.com/angularjs-digest/6, который создает 10 000 наблюдателей. В современном браузере это занимает чуть менее 6 мс. В Internet Explorer 8 это занимает около 40 мс. Как видите, в наши дни это не проблема даже для медленных браузеров. Есть предостережение: сравнения должны быть простыми, чтобы соответствовать ограничению по времени ... К сожалению, слишком медленно добавлять медленное сравнение в AngularJS, поэтому легко создавать медленные приложения, когда вы не знаете, что вам нужно. делают. Но мы надеемся получить ответ, предоставив инструментальный модуль, который покажет вам, какие медленные сравнения.
Оказывается, что в видеоиграх и графических процессорах используется метод грязной проверки, особенно потому, что он последовательный. Пока они превышают частоту обновления монитора (обычно 50–60 Гц или каждые 16,6–20 мс), любая производительность, превышающая это, является пустой тратой, поэтому вам лучше рисовать больше материала, чем увеличивать FPS.
источник
Миско уже дал отличное описание того, как работают привязки данных, но я хотел бы добавить свой взгляд на проблему производительности с привязкой данных.
Как сказал Миско, около 2000 привязок - это то место, где вы начинаете видеть проблемы, но в любом случае на странице не должно быть более 2000 фрагментов информации. Это может быть правдой, но не каждая привязка данных видна пользователю. Как только вы начнете создавать виджеты или сетки данных с двусторонним связыванием, вы можете легко выполнить 2000 привязок, не имея плохого UX.
Рассмотрим, например, поле со списком, в котором вы можете ввести текст для фильтрации доступных параметров. Этот вид контроля может иметь ~ 150 предметов и все еще быть очень полезным. Если у него есть какая-то дополнительная функция (например, определенный класс для текущей выбранной опции), вы начинаете получать 3-5 привязок для каждой опции. Разместите три из этих виджетов на странице (например, один для выбора страны, другой для выбора города в указанной стране и третий для выбора отеля), и вы уже находитесь в диапазоне от 1000 до 2000 привязок.
Или рассмотрите сетку данных в корпоративном веб-приложении. 50 строк на страницу не лишены смысла, каждая из которых может иметь 10-20 столбцов. Если вы построите это с помощью ng-повторов и / или будете иметь информацию в некоторых ячейках, в которых используются некоторые привязки, вы можете приблизиться к 2000 привязкам только с этой сеткой.
Я считаю, что это огромная проблема при работе с AngularJS, и единственное решение, которое мне удалось найти, - это создание виджетов без двустороннего связывания, вместо использования ngOnce, отмены регистрации наблюдателей и подобных трюков, или создание директивы, которые создают DOM с помощью jQuery и манипулирования DOM. Я чувствую, что это побеждает цель использования Angular в первую очередь.
Я хотел бы услышать предложения о других способах справиться с этим, но тогда, возможно, я должен написать свой собственный вопрос. Я хотел поместить это в комментарии, но это оказалось слишком длинным для этого ...
TL; DR
Привязка данных может вызвать проблемы производительности на сложных страницах.
источник
Путем грязной проверки
$scope
объектаAngular поддерживает простой
array
наблюдателей в$scope
объектах. Если вы проверите любой из них,$scope
вы обнаружите, что он содержитarray
вызываемый$$watchers
.Каждый наблюдатель - это
object
то, что содержит среди прочегоattribute
имя или что-то более сложное.$scope
как грязную.Как определяются наблюдатели
Есть много разных способов определения наблюдателя в AngularJS.
Вы можете явно на .
$watch
attribute
$scope
Вы можете разместить
{{}}
интерполяцию в своем шаблоне (для вас будет создан наблюдатель на текущем$scope
).Вы можете задать директиву, например,
ng-model
определить для вас наблюдателя.$digest
Цикл проверяет все наблюдатель против последнего значенияКогда мы взаимодействуем с AngularJS по обычным каналам (ng-модель, ng-repeat и т. Д.), Директива запускает цикл дайджеста.
Цикл дайджеста - это первый шаг
$scope
в глубину и всех его потомков . Для каждого$scope
object
мы перебираем его$$watchers
array
и оцениваем все выражения. Если новое значение выражения отличается от последнего известного значения, вызывается функция наблюдателя. Эта функция может перекомпилировать часть DOM, повторно вычислить значение$scope
, вызватьAJAX
request
, все, что вам нужно сделать.Каждая область видимости прослеживается, и каждое выражение наблюдения оценивается и проверяется по последнему значению.
Если наблюдатель срабатывает,
$scope
значит он грязныйЕсли сработает наблюдатель, приложение узнает, что что-то изменилось, и
$scope
помечено как грязное.Функции наблюдателя могут изменять другие атрибуты на
$scope
или на родительском элементе$scope
. Если одна$watcher
функция была запущена, мы не можем гарантировать, что наши другие$scope
все еще чисты, и поэтому мы снова выполняем весь цикл дайджеста.Это связано с тем, что AngularJS имеет двустороннюю привязку, поэтому данные могут быть переданы обратно в
$scope
дерево. Мы можем изменить значение на более высокое$scope
, которое уже было переварено. Возможно, мы изменим значение на$rootScope
.Если
$digest
грязный, мы$digest
снова выполняем весь циклМы непрерывно перебираем
$digest
цикл, пока либо цикл дайджеста не станет чистым (все$watch
выражения имеют то же значение, что и в предыдущем цикле), либо мы не достигнем предела дайджеста. По умолчанию этот предел установлен на 10.Если мы достигнем предела дайджеста, AngularJS выдаст ошибку в консоли:
Дайджест сложен для машины, но легок для разработчика
Как вы можете видеть, каждый раз, когда что-то меняется в приложении AngularJS, AngularJS проверяет каждого наблюдателя в
$scope
иерархии, чтобы увидеть, как реагировать. Для разработчика это огромный выигрыш в производительности, поскольку теперь вам практически не нужно писать код проводки, AngularJS просто заметит, изменилось ли значение, и сделает остальное приложение совместимым с этим изменением.С точки зрения машины, хотя это крайне неэффективно и замедлит работу нашего приложения, если мы создадим слишком много наблюдателей. Миско привел цифру в 4000 зрителей, прежде чем ваше приложение будет работать медленнее в старых браузерах.
Этот предел легко достичь, если вы, например,
ng-repeat
более чем большойJSON
array
. Вы можете избежать этого, используя такие функции, как одноразовая привязка для компиляции шаблона без создания наблюдателей.Как избежать создания слишком большого количества наблюдателей
Каждый раз, когда ваш пользователь взаимодействует с вашим приложением, каждый наблюдатель в вашем приложении будет оцениваться как минимум один раз. Большая часть оптимизации приложения AngularJS - это уменьшение количества наблюдателей в вашем
$scope
дереве. Один из простых способов сделать это - одноразовая привязка .Если у вас есть данные, которые будут редко меняться, вы можете связать их только один раз, используя синтаксис ::, например:
или
Привязка будет срабатывать только тогда, когда содержащий шаблон визуализируется и данные загружаются в
$scope
.Это особенно важно, когда у вас есть
ng-repeat
много предметов.источник
Это мое основное понимание. Это может быть неправильно!
$watch
методу.$apply
метод.$apply
в$digest
вызове метода , который проходит через каждый из часов и проверяет , если они изменились с момента последнего$digest
RAN.В обычной разработке синтаксис привязки данных в HTML говорит компилятору AngularJS создать часы для вас, и методы контроллера уже запущены внутри
$apply
. Так что для разработчика приложений все прозрачно.источник
Я задумался об этом сам некоторое время. Без сеттеров как
AngularJS
заметить изменения$scope
объекта? Это опрос их?Что он на самом деле делает, так это: любое «нормальное» место, где вы модифицируете модель, уже
AngularJS
вызывается из кишок , поэтому оно автоматически вызывает$apply
вас после выполнения кода. Скажем, у вашего контроллера есть метод, к которому подключенng-click
какой-то элемент. Поскольку выAngularJS
вызываете вызов этого метода для вас, у него есть шанс сделать это$apply
в соответствующем месте. Аналогично, для выражений, которые отображаются прямо в представлениях, они выполняютсяAngularJS
так, что это делает$apply
.Когда в документации говорится о необходимости вызова
$apply
вручную для внешнегоAngularJS
кода , речь идет о коде, который при запуске не вытекает изAngularJS
самого себя в стеке вызовов.источник
Объясняя с картинками:
Привязка данных требует отображения
Ссылка в области не является точной ссылкой в шаблоне. Когда вы связываете данные двух объектов, вам нужен третий, который слушает первый и модифицирует другой.
Здесь, когда вы изменяете
<input>
, вы касаетесь data-ref3 . И классический механизм связывания данных изменит data-ref4 . Так как же{{data}}
будут двигаться другие выражения?События приводят к $ digest ()
Angular поддерживает
oldValue
иnewValue
любой привязки. И после каждого события Angular знаменитый$digest()
цикл будет проверять список наблюдения, чтобы увидеть, изменилось ли что-то. Эти угловые события являютсяng-click
,ng-change
,$http
завершено ... The$digest()
цикл будет до тех пор , как любойoldValue
отличается отnewValue
.На предыдущем рисунке он заметит, что data-ref1 и data-ref2 изменились.
Выводы
Это немного похоже на яйцо и курицу. Вы никогда не знаете, кто начинает, но, надеюсь, это работает большую часть времени, как ожидалось.
Другое дело, что вы можете легко понять влияние простого связывания на память и процессор. Надеюсь, настольные компьютеры достаточно толстые, чтобы справиться с этим. Мобильные телефоны не так сильны.
источник
Очевидно, что нет периодической проверки того
Scope
, есть ли какие-либо изменения в объектах, прикрепленных к нему. Наблюдаются не все объекты, прикрепленные к области видимости. Область действия прототипа поддерживает $$ watchers .Scope
повторяется только$$watchers
при$digest
вызове.Angular добавляет наблюдателя в $$ watchers для каждого из этих
Функция $ watch принимает три параметра:
В Angular есть интересная вещь, которая называется Digest Cycle. Цикл $ digest начинается в результате вызова $ scope. $ Digest (). Предположим, что вы изменили модель $ scope в функции-обработчике с помощью директивы ng-click. В этом случае AngularJS автоматически запускает цикл $ digest, вызывая $ digest (). Помимо ng-click, есть несколько других встроенных директив / сервисов, которые позволяют вам менять модели (например, ng-model, $ timeout и т. Д.) и автоматически запускает цикл $ digest. Примерная реализация $ digest выглядит следующим образом.
Если мы используем функцию setTimeout () в JavaScript для обновления модели области, Angular не сможет узнать, что вы можете изменить. В этом случае наша обязанность - вызвать $ apply () вручную, что запускает цикл $ digest. Аналогично, если у вас есть директива, которая устанавливает прослушиватель событий DOM и изменяет некоторые модели внутри функции-обработчика, вам нужно вызвать $ apply (), чтобы изменения вступили в силу. Основная идея $ apply заключается в том, что мы можем выполнить некоторый код, который не знает об Angular, этот код все еще может изменить вещи в области видимости. Если мы заключим этот код в $ apply, он позаботится о вызове $ digest (). Грубая реализация $ apply ().
источник
AngularJS обрабатывает механизм привязки данных с помощью трех мощных функций: $ watch () , $ digest () и $ apply () . В большинстве случаев AngularJS будет вызывать $ scope. $ Watch () и $ scope. $ Digest (), но в некоторых случаях вам, возможно, придется вызывать эти функции вручную для обновления с новыми значениями.
$ watch () : -
$ digest () -
$ apply () -
источник
Случилось так, что мне нужно было связать модель данных человека с формой, и я сделал прямое сопоставление данных с формой.
Например, если модель имела что-то вроде:
Контрольный ввод формы:
Таким образом, если вы измените значение контроллера объекта, оно будет автоматически отражено в представлении.
Пример, в котором я передал модель, обновляется из данных сервера, когда вы запрашиваете почтовый индекс и почтовый индекс, основанный на письменной загрузке списка колоний и городов, связанных с этим представлением, и по умолчанию задаете первое значение для пользователя. И я работал очень хорошо, что происходит,
angularJS
иногда требуется несколько секунд, чтобы обновить модель, для этого вы можете поставить счетчик во время отображения данных.источник
Одностороннее связывание данных - это подход, при котором значение берется из модели данных и вставляется в элемент HTML. Нет способа обновить модель из вида. Используется в классических шаблонных системах. Эти системы связывают данные только в одном направлении.
Привязка данных в приложениях Angular - это автоматическая синхронизация данных между компонентами модели и вида.
Привязка данных позволяет вам рассматривать модель как единый источник истины в вашем приложении. Представление является проекцией модели во все времена. Если модель изменяется, представление отражает это изменение и наоборот.
источник
Вот пример привязки данных с AngularJS, используя поле ввода. Позже объясню
HTML-код
Код AngularJS
Как видно из приведенного выше примера, AngularJS использует
ng-model
для прослушивания и просмотра того, что происходит с элементами HTML, особенно сinput
полями. Когда что-то случится, сделай что-нибудь. В нашем случае,ng-model
это привязка к нашему мнению, используя обозначение усов{{}}
. Все, что введено в поле ввода, отображается на экране мгновенно. И в этом прелесть связывания данных, используя AngularJS в его простейшей форме.Надеюсь это поможет.
Смотрите рабочий пример здесь на Codepen
источник
AngularJs поддерживает двухстороннюю привязку данных .
Означает, что вы можете получить доступ к данным View -> Controller & Controller -> View
Например
1)
O / P
Вы можете связать данные в
ng-model
Like: -2)
Вот в приведенном выше примере, что бы ни вводил пользователь ввода, это будет видно в
<div>
теге.Если вы хотите привязать ввод из html к контроллеру: -
3)
Здесь, если вы хотите использовать вход
name
в контроллере, то,ng-model
связывает наш взгляд и представляет его в выражении{{ }}
.ng-model
это данные, которые отображаются пользователю в представлении и с которыми взаимодействует пользователь.Так что легко связать данные в AngularJs.
источник
Angular.js создает наблюдатель для каждой модели, которую мы создаем. Всякий раз, когда модель изменяется, к модели добавляется класс «ng-dirty», поэтому наблюдатель будет наблюдать за всеми моделями, имеющими класс «ng-dirty», и обновлять их значения в контроллере и наоборот.
источник
привязка данных:
Что такое привязка данных?
Всякий раз, когда пользователь изменяет данные в представлении, происходит обновление этого изменения в модели области действия, и наоборот.
Как это возможно?
Краткий ответ: с помощью цикла дайджеста.
Описание: Angular js устанавливает наблюдателя на модель объема, которая запускает функцию слушателя, если в модели есть изменение.
// Dom обновляет код новым значением
});
Так когда и как вызывается функция наблюдателя?
Функция наблюдателя вызывается как часть цикла дайджеста.
Цикл дайджеста вызывается автоматически, как часть угловых js, встроенных в директивы / сервисы, такие как ng-model, ng-bind, $ timeout, ng-click и другие ..., которые позволяют запустить цикл дайджеста.
Функция цикла дайджеста:
т.е.
$rootScope.$apply()
Примечание: $ apply () равно $ rootScope. $ Digest () это означает, что грязная проверка начинается прямо с корня или вершины или родительской области видимости для всех дочерних областей $ в угловом приложении js.
Вышеперечисленные функции работают в браузере IE для упомянутых версий, также просто убедившись, что ваше приложение является приложением angular js, что означает, что вы используете файл сценария фреймворка angularjs, указанный в теге script.
Спасибо.
источник