什么被认为是 Angular 中的观察者?

Posted

技术标签:

【中文标题】什么被认为是 Angular 中的观察者?【英文标题】:What is considered a watcher in Angular? 【发布时间】:2015-10-25 22:23:18 【问题描述】:

在 Angular 中什么是“watchers”?观察者本身是唯一类型的观察者,还是其他 Angular 构造(例如 ngModel 观察者)也是如此?

还是我错过了大局?例如,观察者是否使 ngModel 之类的指令起作用?

更新:有没有办法判断何时存在观察者?在测试中我想知道什么时候调用 scope.$digest()

【问题讨论】:

我强烈建议您观看来自 ng-conf 的名为 "Sasqatch is Real" 的演讲。它讨论了创建手表的所有内容,并显示了您的正常视图最终可能拥有多少手表以及拥有过多手表的影响。 感谢您的链接 -- 似乎正是我要找的。​​span> 【参考方案1】:

要说明 $watch()、$digest() 和 $apply() 的工作原理,请看以下示例:

<div ng-controller="myController">
data.time

<br/>
<button ng-click="updateTime()">update time - ng-click</button>
<button id="updateTimeButton"  >update time</button>
</div>
<script>
var module = angular.module("myapp", []);
var myController1 = module.controller("myController", function($scope) 
    $scope.data =  time : new Date() ;
    $scope.updateTime = function() 
        $scope.data.time = new Date();
    
    document.getElementById("updateTimeButton")
            .addEventListener('click', function() 
        console.log("update time clicked");
        $scope.data.time = new Date();
    );
);
</script>

此示例将 $scope.data.time 变量绑定到插值指令,该指令将变量值合并到 html 页面中。此绑定在 $scope.data.time 变量内部创建一个监视。

该示例还包含两个按钮。第一个按钮附加了一个 ng-click 侦听器。单击该按钮时,会调用 $scope.updateTime() 函数,然后 AngularJS 会调用 $scope.$digest() 以便更新数据绑定。

第二个按钮从控制器函数内部获得一个附加的标准 javascript 事件侦听器。单击第二个按钮时,将执行侦听器函数。如您所见,两个按钮的侦听器函数几乎相同,但是当调用第二个按钮的侦听器函数时,数据绑定不会更新。那是因为在执行第二个按钮的事件侦听器之后没有调用 $scope.$digest()。因此,如果您单击第二个按钮,则 $scope.data.time 变量中的时间会更新,但不会显示新时间。

为了解决这个问题,我们可以在按钮事件监听器的最后一行添加一个 $scope.$digest() 调用,如下所示:

document.getElementById("updateTimeButton")
    .addEventListener('click', function() 
console.log("update time clicked");
$scope.data.time = new Date();
$scope.$digest();
);

除了在按钮侦听器函数中调用 $digest() 之外,您还可以像这样使用 $apply() 函数:

document.getElementById("updateTimeButton")
    .addEventListener('click', function() 
$scope.$apply(function() 
    console.log("update time clicked");
    $scope.data.time = new Date();
);
);

注意 $scope.$apply() 函数是如何从按钮事件监听器内部调用的,以及 $scope.data.time 变量的更新是如何在作为参数传递给 $apply() 的函数内部执行的功能。当 $apply() 函数调用完成时,AngularJS 在内部调用 $digest(),所以所有的数据绑定都会更新。

【讨论】:

【参考方案2】:

观察者(如果我们只获取您所基于的文档)是 Angular 机制,旨在以双向绑定样式观察任何 Angular 摘要周期中的变量或函数结果;不管摘要循环的触发事件是什么。

我会将任何能够根据可能发生的任何事件触发某些代码的 Angular 机制称为“观察者”。

通常,要创建 Watcher,您应该使用:$scope.watch(...)

请注意,最好尽可能避开观察者。 实际上,它们的回调将在每个摘要周期触发以执行脏检查;经常影响性能。

ng-model 与观察者的概念无关。ng-model 只是一种将某些变量从视图绑定到控制器的方法。 它们是两个截然不同的概念。

【讨论】:

有没有办法判断何时存在观察者?在测试中我想知道什么时候调用 scope.$digest() 在 Angular 中,您必须在处理测试时管理自己的摘要角色。因此,摘要通常在 Promise 端抛出。当你想解决一个承诺时,你必须调用一个摘要。此外,当您想在表单组件(如输入)上手动设置 viewValue 时,运行 $scope.$digest() 将允许应用绑定。任何会触发摘要的事件,您都必须手动播放。【参考方案3】:

watchers 只不过是脏检查,它跟踪 旧值与新值

他们在每个摘要周期都得到评估。它可以是范围变量或任何表达式的组合。 Angular 确实会在每个摘要循环中收集所有这些观察者,并将其维护在 $$watchers 数组中。您可以通过在控制器中执行 console.log($scope.$watchers) 来查看有多少观察者。

标记

<body class="container" ng-controller="myCtrl">
  Hello test
  I'm test to show $$watchers test1
  <div ng-show="show">SHowiing this div using ng-show</div>
  <div ng-if="show">SHowiing this div using ng-show</div>
  Watcher is not compulsary that should scope variables '1'
</body>

Plunkr

在上面的代码中猜测有多少观察者,你可以看到有 3 个 插值指令将放置在观察者数组中,然后如果你在控制台中看到$scope.$$watchers,它将显示 5 个观察者。

它怎么会显示 5 个观察者。正如我们只能看到 3,实际上我们使用了 ng-showng-if 指令,它们在内部将 $watch 放置在其属性值中提供的表达式上。 & 这些表达式会在每个摘要循环中进行评估。

您还可以使用 $watch(深度/简单观察) & $watchGroup

你也可以让 watcher 使用$attrs.$observe,它的工作原理和 watch 一样,但它唯一的特殊之处在于它适用于插值变量。

$attrs.$observe('test',function(value)
    alert('')
);

大多数角度指令在内部使用观察器,如ng-repeatng-showng-ifng-includeng-switchng-bind、插值指令、过滤器等。它们在内部放置观察器管理双向绑定的东西。

【讨论】:

所以我想不可能只在特定的一组地方期待观察者。 IE。观察者出现的位置并不总是很明显。我想知道是否有一个可以期待观察者的地方列表(其中角度指令)。 @Gnuey 你能看看更新的答案吗...谢谢 :)

以上是关于什么被认为是 Angular 中的观察者?的主要内容,如果未能解决你的问题,请参考以下文章

Angular 11:不推荐使用订阅:改用观察者?

angular.equals() 占用了 50% 的执行时间

在 Angular 中组合可观察数据的正确方法是啥?

将可观察响应映射为 Angular 中的自定义接口数组

设计模式之观察者模式

AngularJS $watch 的 Angular 等价物是啥?