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

下面是关于如何使用$$postDigest函数的:

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

异常处理

现有对Scope的实现已经逐渐接近在Angular中实际的样子了,但还有些脆弱,因为我们迄今为止没有花精力在异常处理上。

Angular的作用域在遇到错误的时候是非常健壮的:当产生异常的时候,不管在监控函数中,在$evalAsync函数中,还是在$$postDigest函数中,都不会把digest终止掉。我们现在的实现里,在以上任何地方产生异常都会把整个$digest弄挂。

我们可以很容易修复它,把上面三个调用包在try...catch中就好了。

Angular实际上是把这些异常抛给了它的$exceptionHandler服务。既然我们现在还没有这东西,先扔到控制台上吧。

$evalAsync和$$postDigest的异常处理是在$digest函数里,在这些场景里,从已列入计划的程序中抛出的异常将被记录成日志,它后面的还是正常运行:

Scope.prototype.$digest = function() {
 var ttl = 10;
 var dirty;
 this.$beginPhase("$digest");
 do {
  while (this.$$asyncQueue.length) {
   try {
    var asyncTask = this.$$asyncQueue.shift();
    this.$eval(asyncTask.expression);
   } catch (e) {
    (console.error || console.log)(e);
   }
  }
  dirty = this.$$digestOnce();
  if (dirty && !(ttl--)) {
   this.$clearPhase();
   throw "10 digest iterations reached";
  }
 } while (dirty);
 this.$clearPhase();

 while (this.$$postDigestQueue.length) {
  try {
   this.$$postDigestQueue.shift()();
  } catch (e) {
   (console.error || console.log)(e);
  }
 }
};

监听器的异常处理放在$$digestOnce里。

Scope.prototype.$$digestOnce = function() {
 var self = this;
 var dirty;
 _.forEach(this.$$watchers, function(watch) {
  try {
   var newValue = watch.watchFn(self);
   var oldValue = watch.last;
   if (!self.$$areEqual(newValue, oldValue, watch.valueEq)) {
    watch.listenerFn(newValue, oldValue, self);
    dirty = true;
   }
   watch.last = (watch.valueEq ? _.cloneDeep(newValue) : newValue);
  } catch (e) {
   (console.error || console.log)(e);
  }
 });
 return dirty;
};

现在我们的digest循环碰到异常的时候健壮多了。

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

销毁一个监听器

当注册一个监听器的时候,一般都需要让它一直存在于整个作用域的生命周期,所以很少会要显式把它移除。也有些场景下,需要保持作用域的存在,但要把某个监听器去掉。

Angular中的$watch函数是有返回值的,它是个函数,如果执行,就把刚注册的这个监听器销毁。想在我们这个版本里实现这功能,只要返回一个函数在里面把这个监控器从$$watchers数组去除就可以了:

Scope.prototype.$watch = function(watchFn, listenerFn, valueEq) {
 var self = this;
 var watcher = {
  watchFn: watchFn,
  listenerFn: listenerFn,
  valueEq: !!valueEq
 };
 self.$$watchers.push(watcher);
 return function() {
  var index = self.$$watchers.indexOf(watcher);
  if (index >= 0) {
   self.$$watchers.splice(index, 1);
  }
 };
};

      

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

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