全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

AngularJS报错$apply already in progress的解决方法分析

本文实例分析了AngularJS报错$apply already in progress的解决方法。分享给大家供大家参考,具体如下:

如果我们使用了AngularJS中的$scope.$apply()或者$scope.$digest(),我们很可能会遇到类似下面的错误,虽然这个错误没有太大影响,但是在日志中看起来还是很不爽的,日志中记录的异常或者错误,就应该是需要关注和解决的问题,否则就没有必要出现在日志中了。

Error: [$rootScope:inprog] $apply already in progress
http://errors.angularjs.org/1.3.13/$rootScope/inprog?p0=%24apply
  at angular.js:63
  at beginPhase (angular.js:14755)
  at Scope.$apply (angular.js:14499)
  at new <anonymous> (1%20-%20%E5%89%AF%E6%9C%AC.html:10)
  at Object.invoke (angular.js:4185)
  at extend.instance (angular.js:8454)
  at angular.js:7700
  at forEach (angular.js:331)
  at nodeLinkFn (angular.js:7699)
  at compositeLinkFn (angular.js:7078)

下面这段代码就会报上面这个错误:

var myModule = angular.module('myModule', []);
myModule.controller("ctrl_1",function($scope){
$scope.value = "aty";
$scope.$apply();
//$scope.$digest();
});

这个错误其实很好理解:angularJS框架本身已经在做脏数据检测了,我们没有必要再手动调用$apply或者$digest。这里自然而然出现了一个疑问:什么时候需要我们手动调用$apply或者$digest,什么时候不需要呢?这是个好问题,我现在也不知道,目前我只能列出自己在项目中遇到的2种需要手动调用$apply的情况。

情况1:controller中如果有异步操作,比如ajax回调,timeout延时等。可以这么理解:由于异步(延迟)的存在,当开始执行回调函数的时候,angularJS自身controller中的脏值检测已经结束,无法检测到回调函数导致数据的变化。

<html>
 <head>
  <script src="jquery-1.11.1.min.js"></script>
  <script src="angular.js"></script>
  <script>
    var myModule = angular.module('myModule', []);
    myModule.controller("ctrl_1",function($scope){
      $scope.text = "place";
      setTimeout(function(){
        $scope.text = "value setted after time out";
        $scope.$apply();//必需手动进行脏值检测,否则数据无法刷新到界面
      },1000);
    });
    $(function(){
      angular.bootstrap($("#div1")[0], ["myModule"]);
    })
  </script>
 </head>
 <body>
  <div id="div1" ng-controller="ctrl_1">
    <div>{{text}}</div>
    <input id="btn" type="button" value="jquery-event"></input>
  </div>
 </body>
</html>

这段代码如果没有调用$scope.$apply()的话,数据是不会刷新到界面上的。

情况2:在jQuery代码中修改$scope中的数据。这种情况是在angular框架之外操作$scope中的数据,angular不能检测到数据变化是正常的。

<html>
 <head>
  <script src="jquery-1.11.1.min.js"></script>
  <script src="angular.js"></script>
  <script>
    var myModule = angular.module('myModule', []);
    myModule.controller("ctrl_1",function($scope){
      $scope.text = "place";
    });
    $(function(){
      angular.bootstrap($("#div1")[0], ["myModule"]);
      $("#btn").click(function(){
        var $scope = $("#btn").scope();
        $scope.text = "value setted in jquery";
        $scope.$apply();
      });
    })
  </script>
 </head>
 <body>
  <div id="div1" ng-controller="ctrl_1">
    <div>{{text}}</div>
    <input id="btn" type="button" value="jquery-event"></input>
  </div>
 </body>
</html>

在JQuery的事件处理函数中,我们能够通过dom拿到其关联的$scope对象,进而修改$scope中的数据。这种情况下,也必需要手动调用$scope.$apply()。

也就是说我们必须要清楚哪儿些情况需要手动$apply,哪儿些情况不需要手动$apply,这看起来很简单,实际上并不是这样的。看一段我们项目中的代码:

var myModule = angular.module('myModule', []);
myModule.controller("ctrl_1",function($scope){
  $scope.listItems = [];
  $scope.loadListFromService = function(){
    Spl.MessageProcessor.loadData({
          serviceId : "url",
          data : {},
          success : function(json) {
            $scope.listItems = json.results;
      // 要不要$scope.$apply()?
          },
          error: function() {
            console.error("invoke service["+optionsJson.serviceId+"] error.");
          }
    });
  }
  $scope.loadListFromService();
});

loadData()这个函数很像ajax回调,确实是这样的,这个API不过是做了一点封装,大致代码如下:

function loadData(options)
{
  // 从本地缓存中读取,很快
  var dataInCache = U.loadDataFromCache(options.serviceId);
  if(dataInCache)
  {
    options.success(dataInCache);
  }
  else
  {
    //异步ajax
    U.readDataFromServer(options.serviceId, options.data, function(response){
      options.success(response);
    });
  }
}

由于缓存的影响,$scope.loadListFromService()变得不再那么可控,如果本地已经有缓存了,那直接读取缓存是很快的,这个时候不需要手动$apply;如果是第一次,本地没有缓存,那么就变成了情况1,我们需要手动$apply。显然调用loadData()函数的地方,不需要也不应该关注到底有没有缓存的存在,这个时候判断需要不要手动$apply就没有那么容易的。简单粗暴的方式,不管怎么样都手动调用下$scope.$apply(),这样功能不会有问题,但是日志中就不可避免要出现文中开头提到的错误。

angular中的$scope中提供了一个$$phase变量,如果这个变量的值是"$digest" 或者"$apply",就代表angular自身已经在做脏值检测了,不需要我们再去调用$apply或者$digest;否则的话就需要我们手动调用$apply或者$digest了。利用这个属性,我们就可以方便解决上面的错误了,判断一下呗。下面是一个工具函数,好理解吧。

function safeApply(scope, fn) {
  (scope.
phase||scope.$root.
phase) ? fn() : scope.$apply(fn);
}

最后提一下,$digest、$apply、$$phase这些属性或者方法其实都是$scope中的私有的,最好不要使用。如果你用到了这些方法,基本可以断言你的代码存在问题,没有按照angular的方式来组织代码。比如情况1中的setTimeout,完全可以用angular中的$timeout代替,这才是推荐的方式,而不是通过$apply来补救。

<html>
 <head>
  <script src="jquery-1.11.1.min.js"></script>
  <script src="angular.js"></script>
  <script>
    var myModule = angular.module('myModule', []);
    myModule.controller("ctrl_1",function($scope, $timeout){
      $scope.text = "place";
      $timeout(function(){
        $scope.text = "value setted after time out";
      },1000);
    });
    $(function(){
      angular.bootstrap($("#div1")[0], ["myModule"]);
    })
  </script>
 </head>
 <body>
  <div id="div1" ng-controller="ctrl_1">
    <div>{{text}}</div>
    <input id="btn" type="button" value="jquery-event"></input>
  </div>
 </body>
</html>

所以解决“$apply already in progress”最好的方式,就是不要使用$scope.$apply()或者$scope.$digest()。

更多关于AngularJS相关内容感兴趣的读者可查看本站专题:《AngularJS入门与进阶教程》及《AngularJS MVC架构总结》

希望本文所述对大家AngularJS程序设计有所帮助。


# AngularJS  # 报错  # $apply  # already  # in  # progress  # 解决方法  # angularJS中$apply()方法详解  # 浅谈angular.js中实现双向绑定的方法$watch $digest $apply  # AngularJS中的$watch()  # $digest()和$apply()区分  # 全面解析Angular中$Apply()及$Digest()的区别  # AngularJS中$apply方法和$watch方法用法总结  # Angular项目中$scope.$apply()方法的使用详解  # angularjs 中$apply  # $digest  # $watch详解  # Angular.js中$apply()和$digest()的深入理解  # AngularJS双向数据绑定原理之$watch、$apply和$digest的应用  # Angularjs中的$apply及优化使用详解  # 不需要  # 回调  # 也不  # 是这样  # 什么时候  # 这段  # 这个时候  # 检测到  # 都是  # 是一个  # 进阶  # 就会  # 是在  # 很好  # 会有  # 相关内容  # 最好的  # 我现在  # 出现在  # 可以用 


相关文章: 网站制作公司排行榜,抖音怎样做个人官方网站  兔展官网 在线制作,怎样制作微信请帖?  如何在云指建站中生成FTP站点?  Dapper的Execute方法的返回值是什么意思 Dapper Execute返回值详解  如何基于云服务器快速搭建网站及云盘系统?  建站主机默认首页配置指南:核心功能与访问路径优化  网站网页制作电话怎么打,怎样安装和使用钉钉软件免费打电话?  公司网站建设制作费用,想建设一个属于自己的企业网站,该如何去做?  建站之星IIS配置教程:代码生成技巧与站点搭建指南  设计网站制作公司有哪些,制作网页教程?  阿里云高弹*务器配置方案|支持分布式架构与多节点部署  建站之星后台密码遗忘或太弱?如何重置与强化?  网站制作大概要多少钱一个,做一个平台网站大概多少钱?  建站之星CMS建站配置指南:模板选择与SEO优化技巧  制作网站建设的公司有哪些,网站建设比较好的公司都有哪些?  小说建站VPS选用指南:性能对比、配置优化与建站方案解析  安徽网站建设与外贸建站服务专业定制方案  如何快速搭建FTP站点实现文件共享?  企业宣传片制作网站有哪些,传媒公司怎么找企业宣传片项目?  广州商城建站系统开发成本与周期如何控制?  如何选择可靠的免备案建站服务器?  制作网站的公司有哪些,做一个公司网站要多少钱?  简单实现Android文件上传  建站之星五站合一营销型网站搭建攻略,流量入口全覆盖优化指南  开心动漫网站制作软件下载,十分开心动画为何停播?  制作宣传网站的软件,小红书可以宣传网站吗?  巅云智能建站系统:可视化拖拽+多端适配+免费模板一键生成  模具网站制作流程,如何找模具客户?  C++中的Pimpl idiom是什么,有什么好处?(隐藏实现)  用v-html解决Vue.js渲染中html标签不被解析的问题  如何通过山东自助建站平台快速注册域名?  成都网站制作公司哪家好,四川省职工服务网是做什么用?  深入理解Android中的xmlns:tools属性  ,怎么在广州志愿者网站注册?  建站之星如何通过成品分离优化网站效率?  网站好制作吗知乎,网站开发好学吗?有什么技巧?  学校建站服务器如何选型才能满足性能需求?  黑客如何通过漏洞一步步攻陷网站服务器?  如何在Golang中使用encoding/gob序列化对象_存储和传输数据  大连网站制作公司哪家好一点,大连买房网站哪个好?  网站制作多少钱一个,建一个论坛网站大约需要多少钱?  如何解决VPS建站LNMP环境配置常见问题?  建站之星后台管理:高效配置与模板优化提升用户体验  如何配置FTP站点权限与安全设置?  头像制作网站在线观看,除了站酷,还有哪些比较好的设计网站?  网站制作培训多少钱一个月,网站优化seo培训课程有哪些?  宝塔新建站点为何无法访问?如何排查?  宝盒自助建站智能生成技巧:SEO优化与关键词设置指南  家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?  打鱼网站制作软件,波克捕鱼官方号怎么注册? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。