【问题标题】:avoid "$digest already in progress" error避免“$digest 已经在进行中”错误
【发布时间】:2015-10-19 14:46:11
【问题描述】:

我定义了以下指令,它包装了 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/http://127.0.0.1:9000/bower_components/angular/angular.js:68:12 开始阶段@http://127.0.0.1:9000/bower_components/angular/angular.js:16273:1 $RootScopeProvider/this.$gethttp://127.0.0.1:9000/bower_components/angular/angular.js:16014:11 .link/http://127.0.0.1:9000/scripts/directives/pagination.js:30:11

pagination.js 的第 30 行是上面标有注释的行

scope.$apply(); 

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

【问题讨论】:

    标签: javascript angularjs


    【解决方案1】:

    您可以尝试$socpe.$applyAsync() 而不是$scope.$apply(),这不会与当前运行的摘要循环冲突。

    $apply on $scope 在直接运行的时候直接尝试运行摘要循环。它不检查是否有任何摘要循环正在进行,并且您运行摘要循环,它会抛出$digest already in progress

    虽然您可以通过使用包装代码$timeout 函数来解决此问题,但我更愿意使用$applyAsync$applyAsync 方法scope

    $timeout 确实运行 digest 循环,但在运行它之前,它会检查是否有任何摘要正在进行中,然后运行将此 digest 循环调用放入队列中,并在运行摘要循环完成后运行它。

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

    Reference Link

    【讨论】:

    • 为什么我不应该总是使用$scope.$applyAsync() 而不是$scope.$apply()
    【解决方案2】:

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

    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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-01-28
      • 2014-10-01
      • 1970-01-01
      • 1970-01-01
      • 2015-07-26
      • 1970-01-01
      • 1970-01-01
      • 2014-03-18
      相关资源
      最近更新 更多