加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Angular双向数据绑定原理之脏检查分析

发布时间:2020-12-17 08:59:48 所属栏目:安全 来源:网络整理
导读:angular双向数据绑定原理 从UI到数据 :UI事件,ajax请求,timeout等。 从数据到UI :脏检查 脏检查 1. 添加监听器 $watcher 为scope中渲染在页面中的每个数据添加监听器$watcher,当添加 $watcher 的数据发生变化时,调用所有watcher对应的listener,执行数

angular双向数据绑定原理

  • 从UI到数据:UI事件,ajax请求,timeout等。
  • 从数据到UI:脏检查

脏检查

1. 添加监听器$watcher

为scope中渲染在页面中的每个数据添加监听器$watcher,当添加$watcher的数据发生变化时,调用所有watcher对应的listener,执行数据变化后的操作。

function $scope() {
    this.$$watchList = [];
}

$scope.prototype.$watch = function (name,getNewValue,listener) {
    var watch = {
        name: name,//scope中的数据名称
        getNewValue: getNewValue,//数据的当前值
        listener: listener || function () {} //数据变化时执行的操作
    };

    this.$$watchList.push(watch);
};

2. 数据改变时调用所有watcher中的listener

$digest里面调用所有watcher

$scope.prototype.$digest = function () {
    var list = this.$$watchList;
    for (var i = 0,l = list.length; i < l; i++) {
        var watch = list[i];
        var newValue = watch.getNewValue();
        var oldValue = watch.last;//第一次执行时oldValue为undefined
        if (newValue != oldValue) {
            watch.listener(newValue,oldValue);
        }
        watch.last = newValue;
    }
};

此时当newValue != oldValue时便执行$watcher对应的listener.
测试:

var scope = new $scope();
scope.hello = 5;
scope.$watch('hello',function () {
        return scope.hello;
    },function (newValue,oldValue) {
      console.log('newValue: ' + newValue + ';oldValue:' + oldValue);
    });
scope.$digest();
scope.hello = 10;
scope.$digest();
scope.hello = 20;
scope.$digest();
scope.hello = 20;
scope.$digest();
scope.hello = 26;
scope.$digest();

newValue: 5;oldValue:undefined
newValue: 10;oldValue:5
newValue: 20;oldValue:10
newValue: 26;oldValue:20

3. 持续监听

然而当在另一个watcher中改变其他watcher中的值时,上面的digest不能监听到变化:

var scope = new $scope();
scope.hello = 5;
scope.hello2 = 15;
scope.$watch('hello',oldValue) {
        console.log('newValue: ' + newValue + ';oldValue:' + oldValue);
});
scope.$watch('hello2',function () {
        return scope.hello2;
    },oldValue) {
        scope.hello = 10;//这里的改变并未检测到
        console.log('newValue: ' + newValue + ';oldValue:' + oldValue);
});
scope.$digest();

newValue: 5;oldValue:undefined
newValue: 15;oldValue:undefined

因此,在scope中值发生变化时需要持续进行digest,在digest中设置所有数据是否为脏的标志dirty,即每次执行digest,若有数据发生变化,就将dirty置为true,若dirtytrue继续执行digest

$scope.prototype.$$digestOnce = function () {
    var dirty;
    var list = this.$$watchList;

    for (var i = 0,l = list.length; i < l; i++) {
        var watch = list[i];
        var newValue = watch.getNewValue();
        var oldValue = watch.last;
        if (newValue !== oldValue) {
            watch.listener(newValue,oldValue);
            // 因为listener操作,已经检查过的数据可能变脏
            dirty = true;
        }
        watch.last = newValue;
    }
    return dirty;
};
$scope.prototype.$digest = function () {
    var dirty = true;
    while (dirty) {
        dirty = this.$$digestOnce();
    }
};
var scope = new $scope();
scope.hello1 = 5;
scope.hello2 = 10;
scope.$watch('hello1',function () {
        return scope.hello1;
    },oldValue) {
        console.log('newValue:' + newValue + '~~~~' + 'oldValue:' + oldValue);
    });
scope.$watch('hello2',oldValue) {
        scope.hello1 = 20;//这里的值被监听到
        console.log('newValue:' + newValue + '~~~~' + 'oldValue:' + oldValue);
    });
scope.$digest();

newValue:5~~~~oldValue:undefined
newValue:10~~~~oldValue:undefined
newValue:20~~~~oldValue:5

4. 防止持续运行digest陷入死循环

然而当在watcher中互相改变对方的值,则会无限次digest,此时陷入死循环,因此在,digest中设置最多执行次数:

$scope.prototype.$digest = function() {
    var dirty = true;
    var checkTimes = 0;
    var maxTime = 10;
    while(dirty) {
        dirty = this.$$digestOnce();
        checkTimes++;
        if(checkTimes > maxTime && dirty){
            console.log("数据持续脏");
            throw new Error("检测超过10次");
        }
    }
};

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读