angularJS中$apply()方法详解
对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的阻力还真是不少。不过我相信,只要下功夫,即使是反人类的设计也不是什么大的问题。
Okay,废话不多说。为了弄明白angular JS为何物,我先是从Scope开始。那么什么是Scope呢?借用官方文档的一段话:
看完后,类比到其他的编程语言上,感觉Scope就像是Data Model的作用域一样,为Expressions的执行提供上下文,暂且先这么理解吧。
Scope的特性
接下来,看看Scope有哪些特性呢?
Scope提供$watch方法监视Model的变化。
Scope提供$apply方法传播Model的变化。
Scope可以继承,用来隔离不同的application components和属性访问权限。
Scope为Expressions的计算提供上下文。
对于这四点特性,因为我之前学习过Actionscript、C++、Java,所以第一、三、四点不难理解,唯独第二点感觉有点云里雾里。本着打破沙锅问到底的原则,我还是通过Google搜到了一些东西。对于有经验的老手,板砖请轻拍!
源起Javascript
首先,乍一看,scope.apply()似乎就是一个使得bindings得到更新的普普通通的方法。但稍微多想一点,为什么我们需要它?一般在什么时候用它呢?用弄明白这两个问题,还得从Javascript说起。在Javascript代码里,都是按照一定顺序来执行的,当轮到一个代码片段执行的时候,浏览器就只会去执行当前的片段,不会做任何其他的事情。所以有时候一些做得不是很好的网页,当点击了某个东西之后会卡住,Javascript的工作方式就是会导致这一现象原因之一!下面我们有一段代码来感受一下:
function buttonClicked () {
alert('the button was clicked');
}
button.addEventListener('click', buttonClicked);
function timerComplete () {
alert('timer complete');
}
setTimeout(timerComplete, 5000);
当加载Javascript代码时,先先找一个一个id叫“clickMe”的按钮,然后添加一个监听器,然后设置超时。等待5秒,会弹出一个对话框。如果刷新页面并立即点击clickMe按钮,会弹出一个对话框,如果你不点击OK,timerComplete函数永远没有机会执行。
如何更新bindings
好了,扯了一些看似不相关的东西之后,我们回归正题。angular JS是怎么知道什么时候数据的变化和页面需要更新的呢?代码需要知道什么时候数据被修改了,但是现在又没有一种方法直接去通知说某个对象上的数据变了(尽管ECMAscript 5正在尝试解决这一问题,但也还是处于实验阶段)。而目前比较主流的策略有以下有两种解决方案。一种是需要用特殊的对象,让所有的数据都只能通过调用对象的方法设置,而不是直接通过property指定。这样的话,所有的修改就可以被记录下来了,就知道什么时候页面需要更新了。这样做的弊端就是我们必须去继承一个特殊的对象。对于赋值也只能通过object.set('key', 'value')而不是object.key=value的方式。在框架中,像EmberJS和KnockoutJS就是这么干的(虽然我都没接触过——囧)。另一种就是angular JS采用的方式,在每一次Javascript代码执行序列执行结束后都去检查是否有数据的改变。这看起来似乎并不高效,甚至严重影响性能。但是angular JS采用了一些比较巧妙的手段解决了这个问题(还没研究过,目前尚不明确)。这么做的好处就是,我们可以随便使用任意对象,对于赋值方式也没有限制,而且对于数据的改变也能觉察到。
对于angular JS采取的这种解决方案,我们关心的是什么时候数据发生了变化,而这也正是scope.apply()派上用场的地方。对于检查绑定的数据到底有没有发生变化,实际上是由scope.digest()完成的,但是我们几乎从来就没有直接调用过这个方法,而是调用scope.apply()方法,是因为在scope.apply()方法里面,它会去调用scope.digest()方法。scope.apply()方法带一个函数或者一个表达式,然后执行它,最后调用scope.digest()方法去更新bindings或者watchers。
什么时候用$apply()
还是那个问题,那我们到底什么时候需要去调用apply()方法呢?情况非常少,实际上几乎我们所有的代码都包在scope.apply()里面,像ng−click,controller的初始化,http的回调函数等。在这些情况下,我们不需要自己调用,实际上我们也不能自己调用,否则在apply()方法里面再调用apply()方法会抛出错误。如果我们需要在一个新的执行序列中运行代码时才真正需要用到它,而且当且仅当这个新的执行序列不是被angular JS的库的方法创建的,这个时候我们需要将代码用scope.apply()包起来。下面用一个例子解释:
$scope.message ="Waiting 2000ms for update";
setTimeout(function () {
$scope.message ="Timeout called!";
// AngularJS unaware of update to $scope
}, 2000);
}
上面的代码执行后页面上会显示:Waiting 2000ms for update。显然数据的更新没有被angular JS觉察到。
接下来,我们将Javascript的代码稍作修改,用scope.apply()包起来。
$scope.message ="Waiting 2000ms for update";
setTimeout(function () {
$scope.$apply(function () {
$scope.message ="Timeout called!";
});
}, 2000);
}
这次与之前不同的是,页面上先会显示:Waiting 2000ms for update,等待2秒后内容会被更改为:Timeout called! 。显然数据的更新被angular JS觉察到了。
NOTE:我们不应该这样做,而是用angular JS提供的timeout方法,这样它就会被自动用apply方法包起来了。
科学是把双刃剑
最后,我们再来瞅一眼scope.apply()和scope.apply(function)方法吧!虽然angular JS为我们做了很多事情,但是我们也因此丢失了一些机会。从下面的伪代码一看便知:
try {
return$eval(expr);
} catch(e) {
$exceptionHandler(e);
} finally {
$root.$digest();
}
}
它会捕获所有的异常并且不会再抛出来,最后都会调用$digest()方法。
总结一下
$apply()方法可以在angular框架之外执行angular JS的表达式,例如:DOM事件、setTimeout、XHR或其他第三方的库。这仅仅是个开始,水还有很深,欢迎大家一起来deep dive
angularJS中$apply()方法详解的更多相关文章
- angularjs $scope.$apply 方法详解
myApp.controller('firstController',function($scope,$interval){ $scope.date = new Date(); setInterval ...
- Js apply 方法 详解
Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- Js apply方法详解,及其apply()方法的妙用
Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- Js apply方法详解
我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这里我做如下笔记,希望和大家 ...
- 深入学习JavaScript: apply 方法 详解(转)——非常好
主要我是要解决一下几个问题: 1. apply和call的区别在哪里 2. 什么情况下用apply,什么情况下用call 3. apply的其他巧妙用法(一般 ...
- JavaScript: apply 方法 详解(转)——非常好
转载自 http://www.cnblogs.com/KeenLeung/archive/2012/11/19/2778229.html 我在一开始看到javascript的函数apply和call ...
- 深入学习JavaScript: apply 方法 详解
我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这里我做如下笔记,希望和大家 ...
- JavaScript之call()和apply()方法详解
简介:apply()和call()都是属于Function.prototype的一个方法属性,它是JavaScript引擎内在实现的方法,因为属于Function.prototype,所以每个Func ...
- [荐]Js apply()和call()方法详解 - http://www.w3cfuns.com/article-5596443-1-1.html
本帖最后由 默默DE人生 于 2013-3-19 13:22 编辑 Js apply方法详解我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文 ...
随机推荐
- maven第二天——重要概念与其它操作
一.在eclipse中建立工程 在day01中我们搭建了eclipse的maven环境,接下来我们开始建立maven项目 1.在eclipse中建立JAVA工程 file->new->ma ...
- flex“深拷贝”
以前在<ActionScript殿堂之路>上就看到过的“深拷贝”概念一直没有好好地在实战中用到过,但是最近在开发过程中,我发现我在编写VO数据对象时的一个老习惯很浪费我的编码时间,这个习惯 ...
- 2-[HTML]--介绍
1.HTML简介 HTML,全称是超文本标记语言(HyperText Markup Language),它是一种用于创建网页的标记语言.标记语言是一种将文本(Text)以及文本相关的其他信息结合起来, ...
- c#总结:datatable的方法大全
最近在做一个数据处理,保存到datatable中,在过程中了解了datatable一些用法,总结一下: //定义 DataTable dt = new DataTable(); //写入列名: htT ...
- 为什么volatile不能保证原子性?
为什么volatile能替代简单的锁,却不能保证原子性?这里面涉及volatile,是java中的一个我觉得这个词在Java规范中从未被解释清楚的神奇关键词,在Sun的JDK官方文档是这样形容vola ...
- while、for循环控制之if、else
if # score=99 # if score>90: # print('优秀') # elif score<60: # print('不及格') # else: # print('良好 ...
- 【Java源码解析】Thread
简介 线程本质上也是进程.线程机制提供了在同一程序内共享内存地址空间运行的一组线程.对于内核来讲,它就是进程,只是该进程和其他一下进程共享某些资源,比如地址空间.在Java语言里,Thread类封装了 ...
- [VB.NET][C#]二维向量的基本运算
前言 在数学中,几何向量指具有大小(Magnitude)和方向的几何对象,它在线性代数中经由抽象化有着更一般的概念.向量在编程中也有着及其广泛的应用,其作用在图形编程和游戏物理引擎方面尤为突出. 基于 ...
- VBA_把相同行一列追加数据到一行
Sub Test() Dim rowsNum, i, j, equalRowsNum As Integer rowsNum = ActiveSheet.UsedRange.Rows.Count '获得 ...
- 解决网速慢时maven仓库访问慢
构建maven项目时会下载很多依赖,会从官网地址下载是个外国网站,访问速度会很慢,但可以通过修改maven的settings.xml文件换成国内的镜像地址就可以加快访问速度: 一.找到settings ...