AngularJS渲染性能分析

本文深入解析AngularJS中渲染性能优化策略,通过实验对比ng-show、ng-if和ng-switch在不同场景下的性能表现,提出优化建议。重点关注元素创建与删除对性能的影响,以及ng-show结合缓存的使用技巧。

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

作者:Jiang, Jilin


AngularJS中,通过数据绑定。可以十分方便的构建页面。但是当面对复杂的循环嵌套结构时,渲染会遇到性能瓶颈。今天,我们将通过一些列实验,来测试AngularJS的渲染性能,对比ng-show,ng-if的使用场景。并对优化进行简要分析。

 

不过在此之前,我们需要先简单过一遍AngularJS相关的代码:

$apply: function(expr) {
  try {
    beginPhase('$apply');
    try {
      return this.$eval(expr);
    } finally {
      clearPhase();
    }
  } catch (e) {
    $exceptionHandler(e);
  } finally {
    try {
      $rootScope.$digest();
    } catch (e) {
      $exceptionHandler(e);
      throw e;
    }
  }
},

beginPhase和clearPhase用于对$rootScope.$$phase进行锁定。如果发现重复进入$apply阶段则抛出异常,以免出现死循环。

$eval: function(expr, locals) {
  return $parse(expr)(this, locals);
},


 $parse调用的是$ParseProvider。由于之后的实验expr不传值,所以$ParseProvider会直接返回空函数noop() {}。因此我们就不做具体的$ParseProvider内容分析了。



在执行完$eval后,会调用$digest方法。让我们看看$digest里有些什么:

$digest: function() {
  var watch, value, last,
      watchers,
      length,
      dirty, ttl = TTL,
      next, current, target = this,
      watchLog = [],
      logIdx, logMsg, asyncTask;

  beginPhase('$digest');
  // Check for changes to browser url that happened in sync before the call to $digest
  $browser.$$checkUrlChange();

  if (this === $rootScope && applyAsyncId !== null) {
    // If this is the root scope, and $applyAsync has scheduled a deferred $apply(), then
    // cancel the scheduled $apply and flush the queue of expressions to be evaluated.
    $browser.defer.cancel(applyAsyncId);
    flushApplyAsync();
  }

  lastDirtyWatch = null;

  do { // "while dirty" loop
    dirty = false;
    current = target;

    while (asyncQueue.length) {
      try {
        asyncTask = asyncQueue.shift();
        asyncTask.scope.$eval(asyncTask.expression, asyncTask.locals);
      } catch (e) {
        $exceptionHandler(e);
      }
      lastDirtyWatch = null;
    }

    traverseScopesLoop:
    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) {
              if ((value = watch.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;
                watch.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, bu
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值