AngularJS: разница между методами $observe и $watch

Я знаю, что как Watchers и Observers вычисляются как только что-то в $scope изменения в AngularJS. Но не мог понять, в чем именно разница между ними.

мое первоначальное понимание заключается в том, что Observers вычисляются для угловых выражений, которые являются условиями на стороне HTML, где as Watchers выполняется, если $scope.$watch() функция выполняется. Правильно ли я мыслю?

4 ответов


$observe () способ по атрибуты object, и как таковой, он может использоваться только для наблюдения / наблюдения за изменением значения атрибута DOM. Он используется/вызывается только внутри директив. Используйте $observe, когда вам нужно наблюдать / наблюдать атрибут DOM, содержащий интерполяцию (т. е. {{}}).
Е. Г., attr1="Name: {{name}}", затем в директиве: attrs.$observe('attr1', ...).
(если вы попробовать scope.$watch(attrs.attr1, ...) это не будет работать из-за {{}}s -- вы получите undefined.) Используйте $watch для всего остального.

$watch () сложнее. Он может наблюдать / наблюдать "выражение", где выражение может быть либо функцией, либо строкой. Если выражение является строкой, то это $ parse ' d (т. е. оценивается как Угловое выражение) в функцию. (Именно эта функция называется каждым циклом дайджеста.) Строковое выражение не может содержать {{}}. $watch-это метод на область объект, поэтому его можно использовать / вызывать везде, где у вас есть доступ к объекту области, следовательно, в

  • контроллер -- любой контроллер -- один, созданный через ng-view, ng-controller или контроллер директивы
  • функция связывания в директиве, так как она также имеет доступ к области

поскольку строки оцениваются как угловые выражения, $watch часто используется, когда вы хотите наблюдать/наблюдать свойство модели / области. Например., attr1="myModel.some_prop", затем в контроллере или функции по ссылке: scope.$watch('myModel.some_prop', ...) или scope.$watch(attrs.attr1, ...) (или scope.$watch(attrs['attr1'], ...)).
(если вы попробовать attrs.$observe('attr1') вы получите строку myModel.some_prop, что, вероятно, не то, что вы хотите.)

как обсуждалось в комментариях к ответу @PrimosK, все $observes и $ watches проверяются каждые дайджест.

директивы с областями изолирования сложнее. Если используется синтаксис"@", вы можете $observe или $ watch атрибут DOM, который содержит интерполяцию (т. е. {{}}). (Причина, по которой он работает с $watch, заключается в том, что синтаксис " @ " делает интерполяция для нас, следовательно, $watch видит строку без {{}}.) Чтобы было легче запомнить, что использовать, когда, я предлагаю использовать $observe и для этого случая.

чтобы проверить все это, я написал Plunker это определяет две директивы. Один (d1) не создает новую область, другой (d2) создает область изоляции. Каждый директива имеет те же шесть атрибутов. Каждый атрибут как $наблюдать, что и часы за $объед.

<div d1 attr1="{{prop1}}-test" attr2="prop2" attr3="33" attr4="'a_string'"
        attr5="a_string" attr6="{{1+aNumber}}"></div>

посмотрите на журнал консоли, чтобы увидеть различия между $observe и $watch в функции связывания. Затем щелкните ссылку и посмотрите, какие $observes и $watches инициируются изменениями свойств, внесенными обработчиком click.

обратите внимание, что при запуске функции link все атрибуты, содержащие {{}}, еще не оцениваются (поэтому при попытке проверить атрибуты, вы получите undefined). Единственный способ увидеть интерполированные значения-использовать $observe (или $watch, если используется область изолирования с"@"). Таким образом, получение значений этих атрибутов является асинхронные операции. (И именно поэтому нам нужны функции $observe и $watch.)

иногда вам не нужно $observe или $watch. Например, если ваш атрибут содержит число или логическое значение (не строку), просто оцените его один раз: attr1="22", тогда, скажем, ваш функция связывания:var count = scope.$eval(attrs.attr1). Если это просто постоянная строка – attr1="my string" – тогда просто использовать attrs.attr1 в вашей директиве (нет необходимости в $eval ()).

см. также сообщение группы Google Vojta около $ watch выражения.


если я правильно понимаю ваш вопрос, вы спрашиваете, в чем разница, если вы регистрируете обратный вызов слушателя с $watch или если вы делаете это $observe.

обратный вызов registerd с $watch запускается, когда $digest выполняется.

обратный вызов зарегистрирован с $observe вызываются при изменении значения атрибутов, содержащих интерполяцию (например,attr="{{notJetInterpolated}}").


внутри директивы вы можете использовать оба из них очень похожи путь:

    attrs.$observe('attrYouWatch', function() {
         // body
    });

или

    scope.$watch(attrs['attrYouWatch'], function() {
         // body
    });

Я думаю, что это довольно очевидно:

  • $observe используется в функции связывания директив.
  • $watch используется для просмотра любых изменений в его значениях.

имейте в виду: обе функции имеют два аргумента,

$observe/$watch(value : string, callback : function);
  • стоимостью: всегда является Строковой ссылкой на наблюдаемый элемент (имя переменной области или имя атрибута директивы смотрел)
  • обратный звонок: функция, которая будет выполняться в форме function (oldValue, newValue)

Я plunker, таким образом, вы можете получить представление об их использовании. Я использовал аналогию с хамелеоном, чтобы было легче представить.


почему $observe отличается от $watch?

watchExpression оценивается и сравнивается с предыдущим значением каждого цикла digest (), Если есть изменение значения watchExpression, вызывается функция watch.

$observe специфичен для просмотра интерполированных значений. Если значение атрибута директивы интерполируется, например dir-attr="{{ scopeVar }}", функция observe будет вызываться только тогда, когда задано интерполированное значение (и, следовательно, когда $digest уже определенные обновления должны быть сделаны). В основном уже есть наблюдатель для интерполяции, и функция $observe piggybacks от этого.

см. $observe & $set in компиляции.js