【问题标题】:AngularJS : Difference between the $observe and $watch methodsAngularJS:$observe 和 $watch 方法之间的区别
【发布时间】:2013-01-30 07:56:19
【问题描述】:

我知道WatchersObservers 都会在$scope 中的某些内容在AngularJS 中发生变化时立即计算。但无法理解两者之间究竟有什么区别。

我最初的理解是,Observers 是针对角度表达式计算的,这些表达式是 HTML 端的条件,在执行 $scope.$watch() 函数时执行 Watchers。我的想法正确吗?

【问题讨论】:

  • 您的编辑没有帮助而且有点反感。请体谅其他前来寻求实际帮助的人。
  • @smalone 已更改。谢谢和抱歉!
  • ????不用担心。感谢修复。

标签: javascript angularjs


【解决方案1】:

$observe()Attributes 对象上的方法,因此只能用于观察/观察DOM 属性的值变化。它仅在指令内部使用/调用。当您需要观察/观察包含插值的 DOM 属性(即 {{}} 的)时,请使用 $observe。
例如,attr1="Name: {{name}}",然后在指令中:attrs.$observe('attr1', ...)
(如果您尝试使用 scope.$watch(attrs.attr1, ...),它会因为 {{}} 而不起作用——您会得到 undefined。)使用 $watch 来处理其他所有事情。

$watch() 比较复杂。它可以观察/观察“表达式”,其中表达式可以是函数或字符串。如果表达式是字符串,则将$parse'd(即,评估为Angular expression)转换为函数。 (每个摘要循环都会调用此函数。)字符串表达式不能包含 {{}}。 $watch 是Scope 对象上的一个方法,因此它可以在您可以访问范围对象的任何地方使用/调用,因此在

  • 控制器 -- 任何控制器 -- 通过 ng-view、ng-controller 或指令控制器创建的控制器
  • 指令中的链接函数,因为它也可以访问范围

因为字符串被评估为 Angular 表达式,所以当您想要观察/观察模型/范围属性时,经常使用 $watch。例如,attr1="myModel.some_prop",然后在控制器或链接函数中:scope.$watch('myModel.some_prop', ...)scope.$watch(attrs.attr1, ...)(或 scope.$watch(attrs['attr1'], ...))。
(如果你尝试attrs.$observe('attr1'),你会得到字符串myModel.some_prop,这可能不是你想要的。)

正如 cmets 在 @PrimosK 的回答中所讨论的,所有 $observes 和 $watches 都会在每个 digest cycle 进行检查。

具有隔离作用域的指令更复杂。如果使用 '@' 语法,您可以 $observe 或 $watch 包含插值(即 {{}} 的)的 DOM 属性。 (它与 $watch 一起工作的原因是因为 '@' 语法为我们执行了interpolation,因此 $watch 看到一个没有 {{}} 的字符串。)为了更容易记住何时使用哪个,我建议在这种情况下也使用 $observe。

为了帮助测试所有这些,我写了一个Plunker,它定义了两个指令。一个 (d1) 不创建新范围,另一个 (d2) 创建隔离范围。每个指令都有相同的六个属性。每个属性都是 $observe'd 和 $watch'ed。

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

查看控制台日志,看看 $observe 和 $watch 在链接功能上的区别。然后点击链接,看看哪些 $observes 和 $watches 是由点击处理程序所做的属性更改触发的。

请注意,当链接函数运行时,尚未评估任何包含 {{}} 的属性(因此,如果您尝试检查属性,您将得到 undefined)。查看插值的唯一方法是使用 $observe(如果使用带有 '@' 的隔离范围,则使用 $watch)。因此,获取这些属性的值是一个异步操作。 (这就是我们需要 $observe 和 $watch 函数的原因。)

有时您不需要 $observe 或 $watch。例如,如果你的属性包含一个数字或一个布尔值(不是字符串),只需计算一次:attr1="22",然后在你的链接函数中:var count = scope.$eval(attrs.attr1)。如果它只是一个常量字符串——attr1="my string"——那么只需在你的指令中使用attrs.attr1(不需要$eval())。

另请参阅 Vojta's google group post 关于 $watch 表达式。

【讨论】:

  • 很好的答案!你知道为什么ng-src/ng-href 使用attr.$observe 而不是scope.$watch 吗?
  • +1 为 AngularJS 教皇!每次我在 Stack 中搜索有关我最新的 Angular 问题的一些信息时,我都不可避免地会阅读@MarkRajcok 接受的答案。
  • 感谢您的精彩帖子。 scope.$eval(item) 真的很有帮助。如果 item 是 json 字符串,则转换为 json 对象。
  • 你能比较一下 scope.$eval 和 scope.$evalAsync,当我想将对象表达式作为指令参数传递时,我有时会使用它们。像
    。它允许我将所有配置参数放入一个属性中。
  • @tamakisquare,它们在使用@ 语法时可以互换。我相信没有性能差异(但我没有查看实际的源代码)。
【解决方案2】:

如果我理解你的问题,你问的是,如果你用$watch注册监听器回调,或者你用$observe注册监听回调有什么区别。

$watch 注册的回调在执行$digest 时被触发。

使用$observe 注册的回调在包含插值的属性的值更改时调用(例如attr="{{notJetInterpolated}}")。


Inside 指令你可以以非常相似的方式使用它们:

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

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

【讨论】:

  • 实际上,由于每个更改都会反映在$digest 阶段,因此可以安全地假设$observe 回调将在$digest 中调用。并且$watch 回调也将在$digest 中调用,但无论何时更改值。我认为他们做的工作完全相同:“观察表达式,调用回调值变化”。关键字差异可能只是语法糖,以免使开发人员感到困惑。
  • @fastreload,我完全同意你的评论.. 写得很好!
  • @fastreload... 感谢您的精彩解释。如果我理解正确的话,观察者是用于 Angular 表达式的。我说的对吗?
  • @PrimosK:为我之前的评论添加你。
  • @Abilash 观察者用于观察 dom 属性,而不仅仅是表达式。所以如果你自己改变属性值,就会在下一个摘要循环中体现出来。
【解决方案3】:

我认为这很明显:

  • $observe 用于指令的链接功能。
  • $watch 用于作用域上观察其值的任何变化。

记住:这两个函数都有两个参数,

$observe/$watch(value : string, callback : function);
  • value :始终是对被监视元素的字符串引用(作用域变量的名称或要监视的指令属性的名称)
  • callback : 要执行的函数,形式为function (oldValue, newValue)

我已经创建了plunker,因此您实际上可以掌握它们的使用情况。我使用了变色龙的类比来使其更容易描绘。

【讨论】:

  • 它的用法非常明显。但为什么是这个问题。马克总结得很好。
  • 我认为参数可能会被切换 - 它似乎将 newValue,然后 oldValue 传递给 attrs.$observe() 。 . .
【解决方案4】:

为什么 $observe 与 $watch 不同?

每个 digest() 循环都会评估 watchExpression 并与之前的值进行比较,如果 watchExpression 值发生变化,则调用 watch 函数。

$observe 专门用于观察插值。如果指令的属性值被插值,例如dir-attr="{{ scopeVar }}",则仅在设置插值时调用观察函数(因此当$digest 已经确定需要进行更新时)。基本上已经有一个插值的观察者,并且 $observe 函数捎带了它。

查看compile.js中的$observe和$set

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-27
    • 2015-08-02
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 2021-07-15
    • 2011-02-02
    相关资源
    最近更新 更多