深入理解Angularjs 脏值检测(7)

$eval的实现很简单:

Scope.prototype.$eval = function(expr, locals) {
 return expr(this, locals);
};

$eval的使用一样很简单:

http://jsbin.com/UzaWUC/1/embed?js,console

那么,为什么要用这么一种明显很多余的方式去执行一个函数呢?有人觉得,有些代码是专门与作用域的内容打交道的,$eval让这一切更加明显。$scope也是构建$apply的一个部分,后面我们就来讲它。

然后,可能$eval最有意思的用法是当我们不传入函数,而是表达式。就像$watch一样,可以给$eval一个字符串表达式,它会把这个表达式编译,然后在作用域的上下文中执行。我们将在这个系列的后面部分实现这些。

$apply - 集成外部代码与digest循环

可能Scope上所有函数里最有名的就是$apply了。它被誉为将外部库集成到Angular的最标准的方式,这话有个不错的理由。

$apply使用函数作参数,它用$eval执行这个函数,然后通过$digest触发digest循环。下面是一个简单的实现:

Scope.prototype.$apply = function(expr) {
 try {
  return this.$eval(expr);
 } finally {
  this.$digest();
 }
};

$digest的调用放置于finally块中,以确保即使函数抛出异常,也会执行digest。

关于$apply,大的想法是,我们可以执行一些与Angular无关的代码,这些代码也还是可以改变作用域上的东西,$apply可以保证作用域上的监听器可以检测这些变更。当人们谈论使用$apply集成代码到“Angular生命周期”的时候,他们指的就是这个事情,也没什么比这更重要的了。

这里是$apply的实践:

http://jsbin.com/UzaWUC/2/embed?js,console

延迟执行 - $evalAsync

在JavaScript中,经常会有把一段代码“延迟”执行的情况 - 把它的执行延迟到当前的执行上下文结束之后的未来某个时间点。最常见的方式就是调用setTimeout()函数,传递一个0(或者非常小)作为延迟参数。

这种模式也适用于Angular程序,但更推荐的方式是使用$timeout服务,并且使用$apply把要延迟执行的函数集成到digest生命周期。

但在Angular中还有一种延迟代码的方式,那就是Scope上的$evalAsync函数。$evalAsync接受一个函数,把它列入计划,在当前正持续的digest中或者下一次digest之前执行。举例来说,你可以在一个监听器的监听函数中延迟执行一些代码,即使它已经被延迟了,仍然会在现有的digest遍历中被执行。

我们首先需要的是存储$evalAsync列入计划的任务,可以在Scope构造函数中初始化一个数组来做这事:

function Scope() {
 this.$$watchers = [];
 this.$$asyncQueue = [];
}

      

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/219.html