$digest、$apply以及$$Phase,简单的运行原理

AngularJS的双向数据绑定基于$digest循环的脏值检测。当新值与旧值不等时,执行相关代码。$digest在指令执行后被$apply触发,通过$rootScope作用域进行。$$Phase是AngularJS内部状态标志,表示$apply或$digest状态。AngularJS使用$和$$前缀区分公共和私有对象,避免命名冲突。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考资料:
angularJs权威指南 第23章
angularJs 核心源码浅析 http://dengkunli.com/angular-source-code-series-one/?utm_source=tuicool&utm_medium=referral

根据上述的文章和连接,已经很详细的讲述了相关问题。以下是自己的简单理解:
核心原理:AngularJs双向数据绑定是基于“脏值检测”($digest循环中提供)的功能实现的。即是指当且仅当“新值”与“旧值”不相等时执行此功能代码。
$digest中脏值检测代码如下:

do { // "traverse the scopes" loop
  if ((watchers = current.$$watchers)) {
    // process our watches
    length = watchers.length;
    while (length--) {
      try {
        watch = watchers[length];
        // Most common watches are on primitives, in which case we can short
        // circuit it with === operator, only when === fails do we use .equals
        if (watch) {
          get = watch.get;
          if ((value = get(current)) !== (last = watch.last) &&
              !(watch.eq
                  ? equals(value, last)
                  : (typeof value === 'number' && typeof last === 'number'
                     && isNaN(value) && isNaN(last)))) {
            dirty = true;
            lastDirtyWatch = watch;
            watch.last = watch.eq ? copy(value, null) : value;
            fn = watch.fn;
            fn(value, ((last === initWatchVal) ? value : last), current);
            if (ttl < 5) {
              logIdx = 4 - ttl;
              if (!watchLog[logIdx]) watchLog[logIdx] = [];
              watchLog[logIdx].push({
                msg: isFunction(watch.exp) ? 'fn: ' + (watch.exp.name || watch.exp.toString()) : watch.exp,
                newVal: value,
                oldVal: last
              });
            }
          } else if (watch === lastDirtyWatch) {
            // If the most recently dirty watcher is now clean, short circuit since the remaining watchers
            // have already been tested.
            dirty = false;
            break traverseScopesLoop;
          }
        }
      } catch (e) {
        $exceptionHandler(e);
      }
    }
  }
  // Insanity Warning: scope depth-first traversal
  // yes, this code is a bit crazy, but it works and we have tests to prove it!
  // this piece should be kept in sync with the traversal in $broadcast
  if (!(next = ((current.$$watchersCount && current.$$childHead) ||
      (current !== target && current.$$nextSibling)))) {
    while (current !== target && !(next = current.$$nextSibling)) {
      current = current.$parent;
    }
  }
} while ((current = next));

那么,我们的问题来了。AngularJS是怎么确保动态监听数据的变化的呢:首先再其自己内部的指令后调用了$apply()。再通过其调用$digest()(注意在此过程中调用的是$rootScope作用域上的)。

$$Phase:AngularJS内部的状态标志位,并且$scope.$$Phase返回字符串以标识“$apply” “$digest”及“”状态。

为防止与您的代码意外的名称冲突,AngularJS将公共对象的$名称与私有对象的名称前缀$$。请不要在代码中使用$或$$前缀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值