理解Angular的$ apply()和$ digest()

$apply()并且$digest()是AngularJS的两个核心,有时令人困惑的方面。要了解AngularJS如何工作,需要充分了解如何$apply()$digest()工作。本文旨在解释$apply()$digest()本来面目,以及他们如何能在你的一天到一天AngularJS编程有用的。

$apply$digest探索

AngularJS提供了一个非常棒的功能,被称为双向数据绑定,大大简化了我们的生活。数据绑定意味着当您在视图中更改某些内容时,scope模型将自动更新。类似地,只要scope模型发生变化,视图就会以新值更新。AngularJS如何做?当您编写一个表达式({{aModel}})后,Angular会在scope模型中设置一个观察者,随后模型更改时会更新该视图。watcher就像你在AngularJS设置任何观察者:

$scope.$watch('aModel', function(newValue, oldValue) {
  //update the DOM with newValue
});

传递给的第二个参数$watch()被称为侦听器函数,每当aModel更改的值被调用我们很容易理解,当aModel调用此调用者的值时,更新HTML中的表达式。但是,还有一个大问题!Angular如何计算出什么时候调用这个监听器函数?换句话说,AngularJS如何知道何时aModel改变它可以调用相应的侦听器?它是否定期运行功能以检查scope模型的值是否已更改?那么这是$digest循环的步骤。

这是$digest观察者被解雇周期。当观察者被触发时,AngularJS评估scope模型,如果它已经改变,则调用相应的监听器函数。所以,我们的下一个问题是这个$digest循环何时开始。

这个$digest循环是由于调用而开始的$scope.$digest()假设您scope通过ng-click指令更改处理函数中的模型。在这种情况下,AngularJS $digest通过调用自动触发一个循环$digest()$digest循环开始时,它会触发每个观察者。这些观察者检查scope模型的当前值是否与上次计算的值不同。如果是,则执行相应的监听器功能。因此,如果您在视图中有任何表达式,它们将被更新。此外ng-click,还有其他一些内置指令/服务,让你可以改变模型(例如ng-model$timeout等),并自动触发一个$digest周期。

到现在为止还挺好!但是,有一个小骗局。在上述情况下,Angular不直接调用$digest()相反,它呼叫$scope.$apply(),反过来调用$rootScope.$digest()作为结果,一个摘要循环从此开始$rootScope,随后访问了所有呼叫观察者的小范围。

现在,我们假设你附加一个ng-click指令到一个按钮,并传递一个函数名称。单击按钮时,AngularJS会将函数调用包含在其中$scope.$apply()因此,您的功能按照惯例执行,更改模型(如果有),并且$digest循环开始确保您的更改反映在视图中。

注意$scope.$apply()自动通话$rootScope.$digest()$apply()功能有两种口味。第一个将函数作为参数,对其进行评估,并触发一个$digest循环。第二个版本没有任何参数,只是$digest在调用时启动一个循环。我们会看到为什么前者是不久以前的首选办法。

$apply()什么时候需要手动操作

如果AngularJS通常将代码包装在$apply()一个$digest循环中,那么什么时候需要$apply()手动执行调用实际上,AngularJS有一件事很清楚。它将仅考虑在AngularJS上下文中完成的模型更改(即,将模型包装在内部的代码$apply())。Angular的内置指令已经执行此操作,因此您所做的任何模型更改都将反映在视图中。但是,如果您更改Angular上下文之外的任何模型,那么您需要通过$apply()手动方式通知Angular的更改这就像告诉Angular,你正在改变一些模型,它应该触发,watchers以便你的改变正确地传播。

例如,如果您使用JavaScript的setTimeout()功能更新scope模型,Angular无法知道您可能会改变什么。在这种情况下,您有责任$apply()手动拨号,这会触发一个$digest周期。类似地,如果您有一个设置DOM事件监听器并更改处理函数内部的一些模型的指令,则需要调用$apply()以确保更改生效。

我们来看一个例子。假设您有一个页面,一旦页面加载,您希望在延迟两秒后显示一条消息。您的实现可能看起来像以下列表中显示的JavaScript和HTML。

通过运行示例,您将看到延迟功能在两秒钟的间隔后运行,并更新scope模型message仍然,视图不更新。原因,你可能已经猜到,我们忘了$apply()手动打电话因此,我们需要更新我们的getMessage()功能,如下所示。

如果您运行此更新的示例,您可以在两秒钟后看到视图更新。唯一的改变是我们把我们的代码里面$scope.$apply()自动地触发$rootScope.$digest()因此,观察者照常照常观看更新。

:顺便问一下,你应该使用$timeout服务,这是尽可能setTimeout()使用自动$apply()让你没有打电话给我们$apply()手动。

另外请注意,在上述代码中,您可以像往常一样完成模型更改,并调用$apply()(no-arg版本)到最后。看看下面的代码段:

$scope.getMessage = function() {
  setTimeout(function() {
    $scope.message = 'Fetched after two seconds';
    console.log('message:' + $scope.message);
    $scope.$apply(); //this triggers a $digest
  }, 2000);
};

上面的代码使用no-arg版本$apply()和工作。请记住,您应该始终使用该版本$apply()接受函数参数。这是因为当你传递一个函数时$apply(),函数调用被封装在一个try...catch块中,并且发生的任何异常将被传递给$exceptionHandler服务。

多少次的$digest循环中运行?

$digest循环运行时,执行观察者以查看scope模型是否已更改。如果它们有,则调用相应的侦听器函数。这导致一个重要的问题。如果监听器功能本身改变了scope模型怎么办?AngularJS如何解释这种变化?

答案是$digest循环不运行一次。在当前循环结束时,它将重新开始,以检查是否有任何模型已更改。这基本上是脏的检查,并且完成以考虑可能由监听器功能完成的任何模型更改。因此,$digest循环保持循环,直到没有更多的模型更改,或者它的最大循环数为10。总是很好保持幂等,并尝试最小化监听器函数内的模型更改。

注意:至少,$digest即使您的监听器功能不更改任何型号也会运行两次。如上所述,它运行一次,以确保模型是稳定的,没有变化。

结论

我希望这篇文章澄清了什么$apply$digest全部。要记住的最重要的一点是,Angular 能否检测到你的改变。如果不能,则必须$apply()手动拨号

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
AngularJS中,$digest是一个循环机制,用于检查和更新作用域中的所有绑定。它会遍历作用域树,并检查每个作用域中的所有watcher。当检测到一个watcher的值发生变化时,$digest会触发这些watcher的回调函数,从而更新相应的视图。 $digest循环由AngularJS自动触发,不需要手动调用。当AngularJS检测到可能发生变化的事件(例如用户输入、HTTP请求的响应等)时,它会自动启动$digest循环。在这个过程中,AngularJS会检查每个作用域中的watcher,并更新视图以反映最新的模型状态。 然而,有时候我们需要在AngularJS上下文之外修改模型,并希望通知AngularJS进行更新。这时就可以使用$apply方法。$apply方法会触发$digest循环,强制AngularJS检查和更新所有作用域中的watcher。 一种常见的使用场景是在使用第三方库或原生JS代码时,需要手动调用$apply方法来通知AngularJS进行更新。在这种情况下,我们可以将修改模型的代码包裹在$apply函数中,以确保AngularJS能够正确地检测到变化并更新相应的视图。 总结起来,$digestAngularJS自动触发的循环机制,用于检查和更新作用域中的所有绑定。而$apply是手动调用的方法,用于通知AngularJS在AngularJS上下文之外的代码中发生了模型的变化,需要进行更新。 :https://www.jb51.net/article/120399.htm :https://stackoverflow.com/questions/41285152/when-to-call-scope-apply-in-angularjs
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值