Devil May Code...

Vergil's Blog

       当AngularJS首次向公众发布之后,就有许多关于它的模型变化监控算法的“阴谋论”。其中最被津津乐道的一种是,怀疑AngularJS使用了某种轮询机制。这种机制可能每隔一小段时间就去检查模型值的变化,如果发现变化,就重绘DOM。所有这些猜测都是错误的。

AngularJS没有使用任何的轮询算法来定期检查模型变化

       AngularJS的模型变化监控机制背后的思路其实是“善后”(Observeat the end of the day),因为引发模型变化的情况是有限的。这些情况包括:

  • DOM事件(例如,用户修改了input的值,然后点击一个按钮,调用了一个JavaScript函数或执行其他操作);
  • XHR相应触发回调;
  • 浏览器的地址变化;
  • 计时器(setTimeout, setInterval)触发回调。

       的确,如果上面的任何一种情况都未发生(用户与页面没有发生任何交互,没有任何XHR响应,没有计时器结束),那么监控模型的变化是没有意义的。此时页面上什么事情也没发生,模型也没有变化,重绘DOM也就毫无必要了。

       AngularJS只会在被明确告知的情况下才会启动它的模型监控机制。为了让这种复杂的机制运作起来,需要在scope对象上执行$apply方法。

       回到之前的simple-model执行,可以在input值每次发生变化后执行$apply方法(这样每次按键的变化都会传播给模型。这也是ng-model执行的模型行为)。

.directive('simpleModel', function($parse){
    return function(scope, element, attrs){
        var modelGetter = $parse(attrs.simpleModel);
        var modelSetter = modelGetter.assign;

        //从model更新DOM
        scope.$watch(modelGetter, function(newVal, oldVal){
            element.val(newVal);
        });

        //从DOM更新model
        element.bind('input', function(){
            scope.$apply(function(){
                modelSetter(scope, element.val());
            });
        });
    }
});

       使用AngularJS的内置指令时,我们完全无需调用$apply方法,就可以看到很多“奇迹”,这一点很让人惊讶。但实际上,内置指令的实现代码中调用了$apply方法。也就是说,标准的指令和服务已经帮我们处理好了模型变化的监控工作($http、$timeout、$location等)。

当在一个作用域上调用$apply方法后,AngularJS就会启动模型变化监控机制。在网络通信、DOM事件、JavaScript计时或浏览器地址发生变化之后,AngularJS标准的服务和指令就会调用$apply方法。


摘自《精通AngularJS》 11.2理解AngularJS的内部运作机制


添加新评论 »

在这里输入你的评论...

Powered by Typecho.