避免“$ digest has in progress”错误

时间:2015-10-19 14:46:12

标签: javascript angularjs

我已经定义了以下指令,该指令包装了UI Bootstrap提供的pagination指令

angular.module('my-module')
  .directive('myPagination', ['$filter', '$window', function ($filter, $window) {

    return {
      restrict: 'EA',
      scope: {
        itemsPerPage: '=',
        totalItems: '=',
        page: '='
      },
      link: function (scope, element, attrs) {
        scope.hiddenElement = true;
        var totalMargin = 200, widthByElement = 41;

        scope.getWindowDimensions = function () {
          return {
            'w': element.width()
          };
        };

        scope.$watch(scope.getWindowDimensions, function (newWidth, oldWidth) {
          // calculate how many page buttons fit in the pagination horizontal bar
          scope.maxSize = parseInt($filter('number')((newWidth.w - totalMargin) / widthByElement, 0));
        }, true);

        angular.element($window).bind('resize', function () {
          // "$digest already in progress" thrown by the following line
          scope.$apply();  
        });

      },
      template: '<div class="text-center paginationSelfCare"  ng-show="totalItems > itemsPerPage">' +
      '<pagination ng-show="totalItems/itemsPerPage <= maxSize" total-items="totalItems" items-per-page="itemsPerPage" ng-model="page" max-size="maxSize" class="pagination pagination-sm" ></pagination>' +
      '<pagination ng-show="totalItems/itemsPerPage > maxSize" total-items="totalItems" boundary-links="true" direction-links="true" previous-text="<" next-text=">" first-text="<<" last-text=">>" items-per-page="itemsPerPage" ng-model="page" max-size="maxSize" class="pagination pagination-sm" ></pagination>' +
      '</div>'
    };
  }]);

如果此指令在一个浏览器选项卡(A)中运行,并且我切换到另一个选项卡(B),那么当我切换回A时,我在浏览器控制台中看到以下错误:

  

错误:[$ rootScope:inprog] $ digest已在进行中   http://errors.angularjs.org/1.4.4/ $ rootScope / inprog?P0 =%24digest   minErr /&LT; @ http://127.0.0.1:9000/bower_components/angular/angular.js:68:12   beginPhase @ http://127.0.0.1:9000/bower_components/angular/angular.js:16273:1   $ RootScopeProvider / $这gethttp://127.0.0.1:9000 / bower_components /角度/ angular.js:16014:11   。链接/&LT; @ http://127.0.0.1:9000/scripts/directives/pagination.js:30:11

pagination.js的第30行是标有上述评论的行

scope.$apply(); 

在致电scope.$apply();之前,有什么我可以检查以避免此问题吗?我正在运行Angular版本1.4.4

2 个答案:

答案 0 :(得分:4)

您可以尝试$socpe.$applyAsync()而不是$scope.$apply(),这绝不会与当前正在运行的摘要周期发生冲突。

$apply上的{p> $scope直接尝试运行摘要周期。它不会检查是否有任何摘要周期,并且您运行摘要循环,它会抛出$digest already in progress

虽然您可以使用包装代码$timeout功能来解决此问题,但我更倾向于使用$applyAsync scope方法。

$timeout确实运行digest周期,但在运行之前,它会检查是否正在进行任何摘要,然后将此digest周期调用运行到队列中并在运行后运行它消化周期完成。

$applyAsync是运行摘要周期的性能改进版本,当您运行此方法时,它首先检查是否正在运行任何摘要周期。如果发现任何正在运行的摘要周期,它会将该块放在该摘要周期中(这意味着您减少了一个摘要周期)。

Reference Link

答案 1 :(得分:0)

你的手表很奇怪。这是通常的方式:

angular.element($window).bind('resize', function () {
  // There are a lot of resize events, we do not need to change smth on each 
  // Once per some time is ok.
  if (attrs.lastResize) {
      $timeout.cancel(attrs.lastResize)
  }

  attrs.lastResize = $timeout(function() {
      // actual code like
      // like scope.maxSize = calc();
  }, 75)
});

你不需要在这里申请,因为你有$ timeout。