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 相关文章推荐
在多个页面使用同一个HTML片段《续》
Mar 04 Javascript
拥抱模块化的JavaScript
Mar 07 Javascript
jquery.messager.js插件导致页面抖动的解决方法
Jul 14 Javascript
原生js实现移动开发轮播图、相册滑动特效
Apr 17 Javascript
BootStrap Validator 版本差异问题导致的submitHandler失效问题的解决方法
Dec 01 Javascript
JS简单实现移动端日历功能示例
Dec 28 Javascript
mockjs,json-server一起搭建前端通用的数据模拟框架教程
Dec 18 Javascript
Vue2.5 结合 Element UI 之 Table 和 Pagination 组件实现分页功能
Jan 26 Javascript
vue+iview 实现可编辑表格的示例代码
Oct 31 Javascript
Vue 用Vant实现时间选择器的示例代码
Oct 25 Javascript
vue 父组件通过$refs获取子组件的值和方法详解
Nov 07 Javascript
vue将data恢复到初始状态 &amp;&amp; 重新渲染组件实例
Sep 04 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
php预定义变量使用帮助(带实例)
2013/10/30 PHP
PHP exif扩展方法开启详解
2014/07/28 PHP
PHP获取音频文件的相关信息
2015/06/22 PHP
关于实现代码语法标亮 dp.SyntaxHighlighter
2007/02/02 Javascript
JavaScript中的Document文档对象
2008/01/16 Javascript
js异或加解密效果代码
2008/06/25 Javascript
SWFObject Flash js调用类
2008/07/08 Javascript
JavaScript获取页面中表单(form)数量的方法
2015/04/03 Javascript
详解JS去重及字符串奇数位小写转大写
2016/12/29 Javascript
Node.js中流(stream)的使用方法示例
2017/07/16 Javascript
vue+express 构建后台管理系统的示例代码
2018/07/19 Javascript
基于JavaScript的数据结构队列动画实现示例解析
2020/08/06 Javascript
JS相册图片抖动放大展示效果的示例代码
2021/01/29 Javascript
[04:26]2014DOTA2国际邀请赛-Newbee顺利进入胜者组决赛 独家专访战神7
2014/07/19 DOTA
python线程锁(thread)学习示例
2013/12/04 Python
以Python的Pyspider为例剖析搜索引擎的网络爬虫实现方法
2015/03/30 Python
Python二分法搜索算法实例分析
2015/05/11 Python
python基础while循环及if判断的实例讲解
2017/08/25 Python
浅谈python和C语言混编的几种方式(推荐)
2017/09/27 Python
Python中顺序表的实现简单代码分享
2018/01/09 Python
Python3.遍历某文件夹提取特定文件名的实例
2018/04/26 Python
Python 存储字符串时节省空间的方法
2019/04/23 Python
对python3.4 字符串转16进制的实例详解
2019/06/12 Python
使用Filters滤镜弥补CSS3的跨浏览器问题以及兼容低版本IE
2013/01/23 HTML / CSS
HTML5的结构和语义(3):语义性的块级元素
2008/10/17 HTML / CSS
美国爆米花工厂:The Popcorn Factory
2019/09/14 全球购物
GWT (Google Web Toolkit)有哪些主要的原件组成?
2015/06/08 面试题
初中政治教学反思
2014/01/17 职场文书
学生感冒英文请假条
2014/02/04 职场文书
股份合作协议书
2014/04/12 职场文书
本科生求职信
2014/06/17 职场文书
汉语言文学毕业求职信
2014/07/17 职场文书
纪委书记群众路线整改措施思想汇报
2014/10/09 职场文书
2015年数学教研工作总结
2015/07/22 职场文书
Python基础之字符串格式化详解
2021/04/21 Python
原生Javascript+HTML5一步步实现拖拽排序
2021/06/12 Javascript