AngularJS 中的 $digest() 和 $apply()

韩瑛
• 阅读 2443

1. 什么时候需要人为调用 $apply()?

AngularJS 只会关心在 AngularJS 的执行上下文中 发生的数据模型(model)的变化(比如: 改变数据的代码在 $apply() 里面)。AngularJS 内建的指令 也会自动触发 $digest 循环, 所以任何数据模型(model)的改变也都会反映到视图中。 但是, 如果更改一个 不在 AngularJS 执行上下文中 的数据模型(model), 就需要人为的调用 $apply() 来提醒 AngularJS 数据发生变化了。

例如, 但使用JavaScript的 setTimeout() 函数来更新一个数据模型的时候, AngularJS 就没有办法知道你改变了数据模型。这种情况下, 就需要调用 $apply() 来触发 $digest 循环了。类似的, 如果自定义了一个指令, 这个指令设置了一个 DOM 事件监听器, 更改数据模型的代码在时间处理函数里, 那么也需要调用 $apply() 来保证更改能反映出来。

DEMO:

HTML 代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <title>demo</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>
    <div ng-app="myApp">
        <div ng-controller="myController">
            Delayed Message: {{message}}
        </div>
    </div>
    <script src="js/angular.js">
    </script>

    <script src="js/apply.js"></script>
</body>

</html>

JS 代码:

var myApp = angular.module('myApp', [])

myApp.controller('myController', ['$scope', '$timeout', function($scope, $timeout) {
    $scope.getMessage = function() {

        // 方法1:
        setTimeout(function() {
            // 把需要写的逻辑放入$apply函数内
            $scope.$apply(function() {
                $scope.message = 'Fetched after 3 seconds'
                console.log('message: ', $scope.message);
            })
        }, 2000)

        // 方法2:

        // $timeout(function() {
        //     $scope.message = 'Fetched after 3 seconds'
        //     console.log('message: ', $scope.message);
        // }, 2000)

        // 方法3:

        // setTimeout(function() {
        //     $scope.message = 'Fetched after 3 seconds'
        //     console.log('message: ', $scope.message);
        //     $scope.$apply() // 这里触发了 $digest循环
        // }, 2000)
    }

    $scope.getMessage()
}])

注意:

但需要延时的时候, 尽可能的使用 $timeout, 这样, 就不用人为的去调用 $apply() 了。
在调用 $apply() 的时候, 应该总是要传入函数参数, 因为当为 $apply() 传入函数的时候, 这个函数在调用的时候是包含在 try..catch 中, 并且任何发生的异常都能够被 $exceptionHandler 服务所接收。

2. $digest 循环要执行多少次呢

$digest 循环并不只是运行一次。在当前循环结束后, 它会再次启动来检查是否有数据发生变化, 这被叫做 脏检查$digest 循环会一直保持循环直到再也没有数据模型发生改变, 或者达到最大的循环次数(10次)。

注意: $digest 至少会循环两次即使监听函数没有更改任何数据模型。它会多运行一次以确保没有数据发生变化。

3. 总结

如果 AngularJS 不能检测到你的更改, 那么就必须人为调用 $apply()

点赞
收藏
评论区
推荐文章
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
巴拉米 巴拉米
5年前
bind、call、apply 区别?如何实现一个bind?
一、作用call、apply、bind作用是改变函数执行时的上下文,简而言之就是改变函数运行时的this指向那么什么情况下需要改变this的指向呢?下面举个例子var name"lucy";const obj{    name:"martin",    say:function (){        co
Wesley13 Wesley13
4年前
java通过sina端口提取股票历史数据并存入MySQL
 1.提取股票代码代码见:http://www.oschina.net/code/snippet\_2688840\_55337(http://www.oschina.net/code/snippet_2688840_55337) 2抓取sina股票的json页面数据;代码见:http://www.oschina.net/code/snip
虾米大王 虾米大王
3年前
java代码073
code073.javapackagepack02;importjava.io.IOException;importjava.io.PrintWriter;importjava.util.UUID;importjavax.servlet.ServletException;importjavax.servlet.annotation.Multip
虾米大王 虾米大王
3年前
java代码092
code092.jsp通过FindServlet类查询分页数据所有图书信息ID图书名称价格数量作者<%Listlist1(List)request.getAttribute("list");for(code089book:list1)%
虾米大王 虾米大王
3年前
java代码099
code099.jspInserttitlehere$pageScope.user.name
Wesley13 Wesley13
4年前
VSCode配置FiraCode和更纱黑体字体
!(https://oscimg.oschina.net/oscnet/c7bb62d935ceb01d3b7fe176322e84ae00d.png)Fira Code下载到FiraCode字体的GitHub(https://www.oschina.net/action/GoToLink?urlhttps%
Stella981 Stella981
4年前
Linux自动检测网站心跳通知shell脚本
!/bin/bashLIST("http://xxxx.com")NAME("评价系统getwindowList接口")for((i0;i<${LIST@};i))doHTTP_CODEcurlo/dev/nullsw"%{http_code}""${LIST
Wesley13 Wesley13
4年前
Oracle:Pivot 转多列并包含多个名称
SELECTFROM(SELECTl.DISTRIBUTOR_ID,d.SKU_CODE,d.WH_CODE,d.ORDER_PACKAGES,d.PRICE,d.YEARLY||d.MONTHLYasYM,d
Stella981 Stella981
4年前
PowerDesigner列名、注释内容互换
在用PowerDesigner时,常常在NAME或Comment中写中文在Code中写英文,Name只会显示给我们看,Code会使用在代码中,但Comment中的文字会保存到数据库TABLE的Description中,有时候我们写好了Name再写一次Comment很麻烦,以下两段代码就可以解决这个问题。在PowerDesigner中PowerDesig