资讯专栏INFORMATION COLUMN

AngularJs1.x解读 $watch 和 $digest

Rainie / 3003人阅读

摘要:对象其实就是一个简单的。和和就像一个硬币的两面。他们组合在一起就是脏检查循环的核心对于数据变化的响应。脏值检测目的只有监控的值发生改变的时候我们才执行对应的。思路存储上一次的值,和这一次值的进行比对。中默认的为,对外暴露可修改。

Scope object

Scope对象其实就是一个简单的POJO(plain old JavaScript Object)。我们可以给它任意的添加属性。

// scope.js
export default class Scope {

}
// test.js
const scope = new Scope();
scope.aProperty = 1;
expect(scope.aProperty).toBe(1);
$watch$digest

$watch$digest就像一个硬币的两面。他们组合在一起就是脏检查循环的核心:对于数据变化的响应。

$watch:
$watch(watchExpression, listener, [objectEquality]);

watchExpression: 监听的数据

listener:数据发生变化的时候调用

objectEquality: 后面多带带说

angularjs中将所有的 watchExpression 存放到一个叫作$$watcher的数组中,因此我们创建一个数组:

$$watchers = [];

$watch(watchFn, listenerFn) {

    const watcher = {
      watchFn,
      listenerFn
    };
    
    this.$$watchers.push(watcher);
} 
$digest:

它遍历scope上的所有watchers,计算 watchExpression ,并且调用它对应的 listenerFn。

_.forEach(this.$$watchers, watcher => {
  watcher.listenerFn();
});
脏值检测

目的:只有监控的值发生改变的时候我们才执行对应的listener。
思路:存储上一次的值,和这一次值的进行比对。

$digest() {
    // 将变量声明提取到循环外面
    let newValue;
    let oldValue;
    
    _.forEach(this.$$watchers, watcher => {
      
      newValue = watcher.watchFn(this);
      // 第一次获取last的时候值为undefined
      oldValue = watcher.last;
      // 只有当新旧值不相等的时候才执行listener
      if (newValue !== oldValue) {
        watcher.last = newValue;
        watcher.listenerFn(newValue, oldValue, this);
      }
    });
}
初始化watch的值

angularjs中的初始化值为一个函数:

function initWatchVal() {}

然后将其赋值给watch的last:

const watcher = {
  watchFn,
  listenerFn,
  last: initWacthVal
};
持续监测

添加一个帮助方法,将所有的watchFn运行一次,返回一个boolean值,表示是否有更新:

$digest() {
  
    let newValue;
    let oldValue;
    // 标记是否为脏
    let dirty;
    // 上来先执行一次看是否所有值发生变化,如果有变化,则第二次执行watch
    do {
      // 初次进来设置为false
      dirty = false;
    
      _.forEach(this.$$watchers, watcher => {
      
        newValue = watcher.watchFn(this);
        // 第一次获取last的时候值为undefined
        oldValue = watcher.last;
        // 只有当新旧值不相等的时候才执行listener
        if (newValue !== oldValue) {
          dirty = true;
          watcher.last = newValue;
          // watcher.listenerFn(newValue, oldValue, this);
          const temp = oldValue === initWacthVal ? newValue : oldValue;
          watcher.listenerFn(newValue, temp, this);
        }
      });
    
    } while (dirty);
    
}
ttl

如果watch一直为不稳定的值,我们需要停止脏检查。angularjs中默认的ttl为10,对外暴露可修改。

// 如果为脏,并且ttl达到0的时候
if (dirty && !(ttl--)) {
    throw "10 digest iterations reached";
}
停止脏检查

添加lastDirtyWatch去判断,看源码。

执行$digest的时候将 lastDirtyWatch = null

当前watcer 和 lastDirtyWatch 相同的时候设置为 null

watch的listener里面包含有watch的时候,重置为 null

基于值的脏检查
$watch(watchExpression, listener, [objectEquality]);

判断是否相等要包含数组和对象,angularjs内置的方法为:

angular.equals(o1, o2);

然后替换原来的新旧值的判断:

// 判断是否相等
function areEqual(newValue, oldValue, valueEq) {
  
  if (valueEq) {
    return _.isEqual(newValue, oldValue);
  } else {
    return newValue === oldValue;
  }

}
销毁监听

angularjs中的销毁是给$watch的时候返回一个方法,当你调用的时候,直接将它从数组中移除。

$watch(watchFn, listenerFn, valueEq) {

    const watcher = {
      watchFn,
      listenerFn,
      valueEq, 
      last: initWacthVal
    };
    
    this.$$watchers.push(watcher);
    // 新加入一个watcher的时候将lastDirtyWatch初始化
    this.lastDirtyWatch = null;

    return () => {
      const index = _.find(this.$$watchers, watcher);
      if (index >= 0) {
        this.$$watchers.splice(index, 1);
      }
    };
}
对内简单的分享,记录下来。参照书名:build your own angularjs

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/97849.html

相关文章

  • webpack 使用指南-绪论

    摘要:在讲解之前先回顾一下笔者在项目开发中的工作流变化时代此时工作流大致为结合插件处理视图处理样式等库此时由于依赖少手动引入各种标签结合调试界面时代利用指令服务控制器将逻辑拆分为多个文件利用编译会将分为全局样式和组件样式下载各种依赖此时任需要手动 在讲解 webpack 之前先回顾一下笔者在项目开发中的工作流变化. jquery 时代 此时工作流大致为 jquery 结合插件处理视图 bo...

    Nosee 评论0 收藏0
  • Angular 学习笔记:$digest 实现原理

    摘要:前缀表示私有变量上述代码实现的并不实用,因为实际上我们需要的是监听的对象数据发生改变时才执行相应的方法。我们使用来约束遍历的最大次数,在中默认次数为。 $watch 和 $digest $watch 和 $digest 是数据绑定中的核心概念:我们可以使用 $watch 在 scope 中绑定 watcher 用于监听 scope 中发生的变化,而 $digest 方法的执行即是遍历 ...

    baiy 评论0 收藏0
  • angular的ViewModel设计

    摘要:换言之,的对应的,此外它还有。它们共同构成的监控系统。和是相辅相成的。两者一起,构成了作用域的核心功能数据变化的响应。迭代的最大值称为。框架设计第三版,敬请期待 angular的ViewModel有一个专门的官方术语叫$scope, 它只是一个普通构造器(Scope)的实例。换言之,它是一个普通的JS对象。为了实现MVVM框架通常宣传的那种改变数据即改变视图的魔幻效果,它得装备上更多更...

    int64 评论0 收藏0
  • angular性能优化心得

    摘要:本文针对的读者具备性能优化的相关知识雅虎条性能优化原则高性能网站建设指南等拥有实战经验。这种机制能减少浏览器次数,从而提高性能。仅会检查该和它的子,当你确定当前操作仅影响它们时,用可以稍微提升性能。 搬运自: http://atian25.github.io/2014/05/09/angular-performace/ 不知不觉,在项目中用angular已经半年多了,踩了很多坑...

    guqiu 评论0 收藏0
  • Angular面试从喜剧到悲剧的十个问题

    摘要:虽然只有个问题,但是覆盖了开发中的各个方面,有基本的知识点,也有在开发过程中遇见的问题,同时也有较为开放性的问题去辨别面试者的基础水准和项目经验如果自己一年前面试肯定是喜剧到悲剧的转变。 showImg(https://segmentfault.com/img/bVyzEN); 虽然只有10个问题,但是覆盖了angular开发中的各个方面,有基本的知识点,也有在开发过程中遇见的问题,同...

    Scholer 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<