You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何修复Error:[$rootScope:inprog]?动态刷新ng-repeat代码优化咨询

AngularJS 问题解答

1. 如何修复 Error:[$rootScope:inprog] 错误?

这个错误本质是Angular的digest循环正在进行时,你又尝试触发了另一个$apply/$digest操作,导致循环冲突。下面是几种靠谱的解决方式:

  • 避免在Angular上下文内调用$apply:像ng-click、$watch回调、$http响应这些场景,本身就处于Angular的digest循环中,完全不需要再手动调用$scope.$apply()——这是最常见的触发原因。
  • 用$timeout延迟执行:如果你是在Angular上下文之外(比如原生JS事件、setTimeout、第三方库回调)需要更新视图,别直接用$apply,改用$timeout,它会自动在当前digest循环结束后触发新的循环,而且语法更简洁:
    $timeout(function() {
      // 这里写你要更新scope的代码,比如$scope.todos = newData;
    });
    
  • 谨慎使用$$phase判断(不推荐):虽然可以通过$rootScope.$$phase检查当前是否处于digest循环,但$$phase是Angular内部API,可能在版本更新中变化,应急可以用,但优先选上面的方法:
    if (!$rootScope.$$phase) {
      $scope.$apply();
    }
    

2. ng-repeat 动态刷新的代码优化

先直接说你的代码问题:完全没必要在$watch回调里调用$apply,也不需要重新赋值$scope.todos = newVal。因为$watch的回调本身就是在digest循环中执行的,newVal已经是$scope.todos的最新值,你这么做不仅多余,还可能触发上面的[$rootScope:inprog]错误。

下面给你正确的实现思路:

情况1:修改数组/对象的引用(推荐,性能更好)

Angular的$watch默认是引用监听,只要你给$scope.todos赋一个新的数组/对象,ng-repeat就会自动刷新视图,不需要额外操作:

// 添加新项时,创建新数组(而不是修改原数组)
$scope.addTodo = function(newTodo) {
  // 用扩展运算符创建新数组
  $scope.todos = [...$scope.todos, newTodo];
  // 或者用concat
  // $scope.todos = $scope.todos.concat([newTodo]);
};

// 替换整个数组
$scope.refreshTodos = function(newTodos) {
  $scope.todos = newTodos; // 直接赋新数组,自动触发刷新
};

情况2:直接修改原数组(比如push/splice)

其实Angular已经对数组的push、pop、splice、shift等方法做了封装,调用这些方法时会自动触发digest循环,ng-repeat会跟着刷新。除非你是在Angular上下文之外修改数组(比如原生click事件、setTimeout),这时候才需要用$timeout或者$apply来触发刷新:

// 正常在Angular上下文内调用push,自动刷新
$scope.addTodo = function(newTodo) {
  $scope.todos.push(newTodo);
};

// 如果是在原生事件里修改,用$timeout
document.getElementById('add-btn').addEventListener('click', function() {
  $timeout(function() {
    $scope.todos.push({text: 'New Todo'});
  });
});

情况3:监听复杂对象的内部变化(尽量避免)

如果todos是嵌套的复杂对象,需要监听内部属性变化,才需要开启$watch的第三个参数true(深度监听),但回调里不需要做任何额外赋值:

// 深度监听todos的内部变化
$scope.$watch('todos', function(newVal) {
  // 这里可以做一些基于newVal的逻辑,比如统计完成数
  $scope.completedCount = newVal.filter(t => t.completed).length;
}, true);

注意:深度监听会遍历对象的所有属性,数据量大时会影响性能,尽量用引用变更的方式替代。

内容的提问来源于stack exchange,提问作者mkip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:26:20