Angularjs中的$apply及优化使用详解


Posted in Javascript onJuly 02, 2018

前言

对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的阻力还真是不少。不过我相信,只要下功夫,即使是反人类的设计也不是什么大的问题。

今天,我们要聊得是Angularjs中的小明星$apply。当我们数据更新了,但是view层却没反应时,总能听到有人说,用apply吧,然后,懵懂无知的我们,在赋值代码后面加了$scope.$apply() ,然后就惊喜的发现。噢,真的更新了。

然而,有些时候,编译器会无情的给你返回

Error: $digest already in progress

那么,导致这些现象的原因时什么的呢?$apply究竟干了啥?听我慢慢到来。

一.$apply的作用

$apply()函数可以从Angular框架的外部让表达式在Angular上下文内部执行。

上面是AngularJs权威教程中的一句话。什么意思呢?

首先,你要清楚,在原生js或者第三方框架下,修改model,是有可能不会触发视图更新的,比如setTimeout、jquery插件。为什么?因为他们脱离了Angularjs的上下文,Angularjs并不能监听到数据的改变。看例子。

1.setTimeout

html:

<p>{{name}}</p>

js:

$scope.name="张三";
setTimeout(function(){
$scope.name = '李四';
//$scope.$apply()
},500)

首先,name等于张三,500ms后,我把他赋值为李四,但是,页面上并没有改变,依然是张三。

而,我们把$scope.$apply()放开,就正常了,张三成功变为李四。

2.第三方插件

html:

<p>Date: <input type="text" id="datepicker"></p>
<p>
<header>所选日期</header>
{{selectedDate}}
</p>

js:

$scope.selectedDate = '';
$( function() {
 $( "#datepicker" ).datepicker({
 onClose: function( selectedDate ) {
 $scope.selectedDate = selectedDate;
 // $scope.$apply();
 }
 });
} );

这是jquery的datepicker插件,当我们选定日期后,下面的日期应该随之显现,而现在却没有。这种情况就必须依靠$apply(),才能更新视图。

以上两种情况,都因为不处于Angularjs上下文中,导致监听不到数据的变化。而$apply究竟干了什么,才导致数据更新正常了呢?

其实$apply相当于一个触发器,它的作用就是触发digest循环,从而更新视图。

在digest是Angularjs的核心,是它实现了神奇的数据绑定。凡是触发事件,必会触发digest循环,比如,我们数值的ng事件,click啊,change,实际上都是触发了digest循环。

所以,我们所做的事,其实就是手动触发了digest循环。关于digest循环,属于题外话,这里不做过多介绍,想深入了解的同学,可以看看书籍,或者百度。

二.更好地运用digest循环

在Angularjs中,除了$apply可以触发digest循环外,还有其他的方法,也可以触发此循环。而且$apply往往时最坏的选择。下面推荐一些更好的选择。

1.$digest

$scope.$digest()的速度要比$apply要快,因为它只更新当前作用域和子作用域的值,对于父作用域时不管的。而$apply还要评估父作用域,这就大大消耗了性能。

2.$timeout

用$timeout去代替你的setTimeout,$timeout作为Angularjs的自带服务,当然时更契合Angularjs环境啦。它会隐性触发digest循环,而且它会延迟执行,会在上一个digest循环完成后的下一刻,触发digest循环,这样就不会出现上文所说的

$digest already in progress

我们把setTime的代码放到$timeout中

$timeout(function(){
$scope.name = '李四';
},500)

这就能正常工作了,看,没有讨厌的apply了!

3.$evalAsync

最推荐的应该时这个方法了。如果当前正好有一个digest循环在执行,那么它就会把导致digest循环的操作,放到当前digest循环中去执行。而$timeout是要等到当前digest循环执行完,再执行一次digest循环才可以。所以evalAsync执行更快,性能更好。我们可以像$timeout那样去调用它,即

$scope.$evalAsync(
   function( $scope ) {
   console.log( "$evalAsync" );
   }
  );

以上,就是今天要说的全部内容。Angularjs中还藏着许多奥秘,和更好的使用方法,希望大家可以深入地研究,分享出更好的文章。

下面是可执行的代码,大家可以探究探究:https://codepen.io/hanwolfxue/pen/yEZbYQ

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
JavaScript 三种创建对象的方法
Oct 16 Javascript
基于jquery的仿百度的鼠标移入图片抖动效果
Sep 17 Javascript
网页加载时页面显示进度条加载完成之后显示网页内容
Dec 23 Javascript
js网页右下角提示框实例
Oct 14 Javascript
jQuery对象和DOM对象之间相互转换的方法介绍
Feb 28 Javascript
jQuery操作动态生成的内容的方法
May 28 Javascript
详解使用JS如何制作简单的ASCII图与单极图
Mar 31 Javascript
基于JavaScript实现多级菜单效果
Jul 25 Javascript
js 判断一个数字是不是2的n次方幂的实例
Nov 26 Javascript
js屏蔽退格键(backspace或者叫后退键与F5)
Feb 10 Javascript
jquery+php后台实现省市区联动功能示例
May 23 jQuery
如何利用React实现图片识别App
Feb 18 Javascript
angularjs 的数据绑定实现原理
Jul 02 #Javascript
vue 解决addRoutes动态添加路由后刷新失效问题
Jul 02 #Javascript
vue中的数据绑定原理的实现
Jul 02 #Javascript
Vue实现双向绑定的原理以及响应式数据的方法
Jul 02 #Javascript
jsonp跨域获取数据的基础教程
Jul 01 #Javascript
vue + webpack如何绕过QQ音乐接口对host的验证详解
Jul 01 #Javascript
关于Vue组件库开发详析
Jul 01 #Javascript
You might like
神族 PROTOSS 概述
2020/03/14 星际争霸
天津市收音机工业发展史
2021/03/04 无线电
比较时间段一与时间段二是否有交集的php函数
2011/05/31 PHP
php中的strpos使用示例
2014/02/27 PHP
JavaScript Prototype对象
2009/01/07 Javascript
Array.prototype 的泛型应用分析
2010/04/30 Javascript
extjs之去除s.gif的影响
2010/12/25 Javascript
Three.js源码阅读笔记(光照部分)
2012/12/27 Javascript
Three.js源码阅读笔记(物体是如何组织的)
2012/12/27 Javascript
ExtJs默认的字体大小改变的几种方法(自己整理)
2013/04/18 Javascript
jQuery+CSS3实现3D立方体旋转效果
2015/11/10 Javascript
JS实现日期时间动态显示的方法
2015/12/07 Javascript
JavaScript中关联原型链属性特性
2016/02/13 Javascript
Javascript将数值转换为金额格式(分隔千分位和自动增加小数点)
2016/06/22 Javascript
详解js界面跳转与值传递
2016/11/22 Javascript
利用jQuery插件imgAreaSelect实现获得选择域的图像信息
2016/12/02 Javascript
百度地图JavascriptApi Marker平滑移动及车头指向行径方向
2017/03/13 Javascript
ejsExcel模板在Vue.js项目中的实际运用
2018/01/27 Javascript
解决vue-quill-editor上传内容由于图片是base64的导致字符太长的问题
2018/08/20 Javascript
js数组的基本使用总结
2021/01/18 Javascript
[02:11]2014DOTA2 TI专访VG战队Fenrir:队伍气氛良好
2014/07/11 DOTA
[01:09:40]Newbee vs Pain 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python常用随机数与随机字符串方法实例
2015/04/09 Python
Python 中迭代器与生成器实例详解
2017/03/29 Python
Python列表推导式与生成器用法分析
2018/08/02 Python
Python Scapy随心所欲研究TCP协议栈
2018/11/20 Python
Django 请求Request的具体使用方法
2019/11/11 Python
CSS3中background-clip和background-origin的区别示例介绍
2014/03/10 HTML / CSS
秋季运动会演讲稿
2014/09/16 职场文书
教师先进个人材料
2014/12/17 职场文书
优秀工作者事迹材料
2014/12/26 职场文书
小学班主任评语
2014/12/29 职场文书
领导参观欢迎词
2015/01/26 职场文书
家访教师心得体会
2016/01/23 职场文书
SpringBoot中HttpSessionListener的简单使用方式
2022/03/17 Java/Android
教你部署vue项目到docker
2022/04/05 Vue.js