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 相关文章推荐
Extjs显示从数据库取出时间转换JSON后的出现问题
Nov 20 Javascript
js setTimeout 参数传递使用介绍
Aug 13 Javascript
PHPMyAdmin导入时提示文件大小超出PHP限制的解决方法
Mar 30 Javascript
JQuery简单实现锚点链接的平滑滚动
May 03 Javascript
Jquery ajax加载等待执行结束再继续执行下面代码操作
Nov 24 Javascript
如何用angularjs制作一个完整的表格
Jan 21 Javascript
jQuery基于函数重载实现自定义Alert函数样式的方法
Jul 27 Javascript
浅谈jquery选择器 :first与:first-child的区别
Nov 20 Javascript
Canvas 制作动态进度加载水球详解及实例代码
Dec 09 Javascript
轻量级JS Cookie插件js-cookie的使用方法
Mar 22 Javascript
解决vue与node模版引擎的渲染标记{{}}(双花括号)冲突问题
Sep 11 Javascript
js节流防抖应用场景,以及在vue中节流防抖的具体实现操作
Sep 21 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代码飞起来的40条小技巧(提升php效率)
2010/04/12 PHP
深入分析使用mysql_fetch_object()以对象的形式返回查询结果
2013/06/05 PHP
php绘制一条弧线的方法
2015/01/24 PHP
php正则表达式获取内容所有链接
2015/07/24 PHP
php 利用socket发送HTTP请求(GET,POST)
2015/08/24 PHP
PHP实现原比例生成缩略图的方法
2016/02/03 PHP
PHP中soap用法示例【SoapServer服务端与SoapClient客户端编写】
2018/12/25 PHP
JavaScipt基本教程之JavaScript语言的基础
2008/01/16 Javascript
hover的用法及live的用法介绍(鼠标悬停效果)
2013/03/29 Javascript
在页面上用action传递参数到后台出现乱码的解决方法
2013/12/31 Javascript
js实现简单鼠标跟随效果的方法
2015/04/10 Javascript
百度多文件异步上传控件webuploader基本用法解析
2016/11/07 Javascript
微信小程序 基础组件与导航组件详细介绍
2017/02/21 Javascript
为Jquery EasyUI 组件加上清除功能的方法(详解)
2017/04/13 jQuery
vue如何引用其他组件(css和js)
2017/04/13 Javascript
layer弹窗插件操作方法详解
2017/05/19 Javascript
JavaScript严格模式下关于this的几种指向详解
2017/07/12 Javascript
深入浅析javascript继承体系
2017/10/23 Javascript
Vue自定义指令结合阿里云OSS优化图片的实现方法
2019/11/12 Javascript
JS通用方法触发点击事件代码实例
2020/02/17 Javascript
使用Webpack 搭建 Vue3 开发环境过程详解
2020/07/28 Javascript
如何编写一个 Webpack Loader的实现
2020/10/18 Javascript
用Python的线程来解决生产者消费问题的示例
2015/04/02 Python
Python中计算三角函数之cos()方法的使用简介
2015/05/15 Python
Python通过90行代码搭建一个音乐搜索工具
2015/07/29 Python
详解Python3中字符串中的数字提取方法
2017/01/14 Python
python实现批量修改图片格式和尺寸
2018/06/07 Python
python 剪切移动文件的实现代码
2018/08/02 Python
pandas去重复行并分类汇总的实现方法
2019/01/29 Python
简单了解python数组的基本操作
2019/11/26 Python
Python eval函数原理及用法解析
2020/11/14 Python
美国受欢迎的女性牛仔裤品牌:DL1961
2016/11/12 全球购物
比利时的在线灯具店:Lampen24.be
2019/07/01 全球购物
中专三年学习的个人自我评价
2013/12/12 职场文书
研究生毕业自我鉴定范文
2014/03/27 职场文书
师德师风自我剖析材料
2014/09/27 职场文书