首页 > 语言 > JavaScript > 正文

深入理解AngularJs-scope的脏检查(一)

2024-05-06 15:15:43
字体:
来源:转载
供稿:网友

进入正文前的说明:本文中的示例代码并非AngularJs源码,而是来自书籍<<Build Your Own AngularJs>>, 这本书的作者仅依赖jquery和lodash一步一步构建出AngularJs的各核心模块,对全面理解AngularJs有非常巨大的帮助。若有正在使用AngulaJs攻城拔寨并且希望完全掌握手中武器的小伙伴,相信能对你理解AngularJs带来莫大帮助,感谢作者。

在这篇文章中,希望能让您理清楚以下几项与scope相关的功能:

1.dirty-checking(脏检测)核心机制,主要包括:$watch 和 $digest;

2.几种不同的触发$digest循环的方式:$eval, $apply, $evalAsync, $applyAsync;

3.scope的继承机制以及isolated scope;

4.依赖于scope的事件循环:$on, $broadcast, $emit.

现在开始我们的第一部分:scope和dirty-checking

dirty-checking(脏检测)原理简述:scope通过$watch方法向this.$$watchers数组中添加watcher对象(包含watchFn, listenerFn, valueEq, last 四个属性)。每当$digest循环被触发时,它会遍历$$watchers数组,执行watcher中的watchFn,获取当前scope上某属性的值(一个watcher对应scope上一个被监听属性),然后去同watcher中的last(上一次的值)做比较,若两值不相等,就执行listenerFn。

function Scope() {  this.$$watchers = []; // 监听器数组  this.$$lastDirtyWatch = null; // 每次digest循环的最后一个脏的watcher, 用于优化digest循环  this.$$asyncQueue = []; // scope上的异步队列  this.$$applyAsyncQueue = []; // scope上的异步apply队列  this.$$applyAsyncId = null; //异步apply信息  this.$$postDigestQueue = []; // postDigest执行队列  this.$$phase = null; // 储存scope上正在做什么,值有:digest/apply/null  this.$root = this; // rootScope  this.$$listeners = {}; // 存储包含自定义事件键值对的对象  this.$$children = []; // 存储当前scope的儿子Scope,以便$digest循环递归}

实际上scope就是一个普通的javascript对象,一个类构造函数,可以通过new进行实例化。根据脏检测的原理,接下来,我们一起看看scope的$watch方法的实现。

/* $watch方法:向watchers数组中添加watcher对象,以便对应调用 */Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {  var self = this;  watchFn = $parse(watchFn);  // watchDelegate: 针对watch expression是常量和 one-time-binding的情况,进行优化。在第一次初始化之后删除watch  if(watchFn.$$watchDelegate) {    return watchFn.$$watchDelegate(self, listenerFn, valueEq, watchFn);  }  var watcher = {    watchFn: watchFn,    listenerFn: listenerFn || function() {},    valueEq: !!valueEq,    last: initWatchVal  };  this.$$watchers.unshift(watcher);  this.$root.$$lastDirtyWatch = null;  return function() {    var index = self.$$watchers.indexOf(watcher);    if(index >= 0) {      self.$$watchers.splice(index, 1);      self.$root.$$lastDirtyWatch = null;    }  };};            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选