• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >JavaScript > AngularJS的脏检查深入分析

AngularJS的脏检查深入分析

作者:Pawn.风为裳 字体:[增加 减小] 来源:互联网 时间:2017-05-11

Pawn.风为裳通过本文主要向大家介绍了angularjs脏检查,angularjs,angularjs怎么读,angularjs优点,angularjs视频教程等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

写在开头

关于Angular脏检查,之前没有仔细学习,只是旁听道说,Angular 会定时的进行周期性数据检查,将前台和后台数据进行比较,所以非常损耗性能。

这是大错而特错的。我甚至在新浪前端面试的时候胡说一通,现在想来真是羞愧难当! 没有深入了解就信口开河实在难堪大任。

最后被拒也是理所当然。

误区纠正

首先纠正误区,Angular并不是周期性触发藏检查。

只有当UI事件,ajax请求或者 timeout 延迟事件,才会触发脏检查。

为什么叫脏检查? 对脏数据的检查就是脏检查,比较UI和后台的数据是否一致!

下面解释:

$watch 对象。

Angular 每一个绑定到UI的数据,就会有一个 $watch 对象。

这个对象包含三个参数

watch = {
 name:'',  //当前的watch 对象 观测的数据名
 getNewValue:function($scope){ //得到新值
  ...
  return newValue;
  },
 listener:function(newValue,oldValue){ // 当数据发生改变时需要执行的操作
  ...
 }
}
</div>

getNewValue() 可以得到当前$scope 上的最新值,listener 函数得到新值和旧值并进行一些操作。

而常常我们在使用Angular的时候,listener 一般都为空,只有当我们需要监测更改事件的时候,才会显示地添加监听。

每当我们将数据绑定到 UI 上,angular 就会向你的 watchList 上插入一个 $watch。

比如:

<span>{{user}}</span>
<span>{{password}}</span>
</div>

这就会插入两个$watch 对象。

之后,开始脏检查。

好了,我们先把脏检查放一放,来看它之前的东西

双向数据绑定 ! 只有先理解了Angular的双向数据绑定,才能透彻理解脏检查 。

双向数据绑定

Angular实现了双向数据绑定。无非就是界面的操作能实事反应到数据,数据的更改也能在界面呈现。

界面到数据的更改,是由 UI 事件,ajax请求,或者timeout 等回调操作,而数据到界面的呈现则是由脏检查来做.

这也是我开始纠正的误区

只有当触发UI事件,ajax请求或者 timeout 延迟,才会触发脏检查。

看下面的例子

<div ng-controller="CounterCtrl">
 <span ng-bind="counter"></span>
 <button ng-click="counter=counter+1">increase</button>
</div>
</div>
function CounterCtrl($scope) {
 $scope.counter = 1;
}

</div>

毫无疑问,我每点击一次button,counter就会+1,因为点击事件,将couter+1,而后触发了脏检查,又将新值2 返回给了界面.

这就是一个简单的双向数据绑定的流程.

但是就只有这么简单吗??

看下面的代码

'use strict';


var app = angular.module('app', []);
app.directive('myclick', function() {
 return function(scope, element, attr) {
  element.on('click', function() {
   scope.data++;
   console.log(scope.data)

  })
 }
})
app.controller('appController', function($scope) {
 $scope.data = 0;
});
</div>
 <div ng-app="app">
  <div ng-controller="appController">
   <span>{{data}}</span>
   <button myclick>click</button>
  </div>
 </div>
</div>

点击后,毫无反应.

试试在 console.log(scope.data) 后面添加 scope.$digest(); 试试?

很明显,数据增加了。如果使用$apply () 呢? 当然可以(后面会接受 $apply 和 $digest 的区别)

为什们呢?

假设没有AngularJS,要让我们自己实现这个类似的功能,该怎么做呢?

<body>
 <button ng-click="increase">increase</button>
 <button ng-click="decrease">decrease</button>
 <span ng-bind="data"></span>
 <script src="app.js"></script>
</body>
</div>
window.onload = function() {
 'use strict';

 var scope = {
  increase: function() {
   this.data++;
  },
  decrease: function decrease() {
   this.data--;
  },
  data: 0
 }

 function bind() {
  var list = document.querySelectorAll('[ng-click]');
  for (var i = 0, l = list.length; i < l; i++) {
   list[i].onclick = (function(index) {
    return function() {
     var func = this.getAttribute('ng-click');
     scope[func](scope);
     apply();
    }
   })(i);
  }
 }

 // apply
 function apply() {
  var list = document.querySelectorAll('[ng-bind]');
  for (var i = 0, l = list.length; i < l; i++) {
   var bindData = list[i].getAttribute('ng-bind');
   list[i].innerHTML = scope[bindData];
  }
 }

 bind();
 apply();
}

</div>

测试一下:

 

可以看到我们没有直接使用DOM的onclick方法,而是搞了一个ng-click,然后在bind里面把这个ng-click对应的函数拿出来,绑定到onclick的事件处理函数中。为什么要这样呢?因为数据虽然变更了,但是还没有往界面上填充,我们需要在此做一些附加操作。

另外,由于双向绑定机制,在DOM操作中,虽然更新了数据的值,但是并没有立即反映到界面上,而是通过 apply() 来反映到界面上,从而完成职责的分离,可以认为是单一职责模式了。

在真正的Angular中,ng-click 封装了click,然后调用一次 apply 函数,把数据呈现到界面上

在Angular 的apply函数中,这里先进行脏检测,看 oldValue 和 newVlue 是否相等,如果不相等,那么讲newValue 反馈到界面上,通过如果通过 $watch 注册了 listener事件,那么就会调用该事件。

脏检查的优缺点

经过我们上面的分析,可以总结:

  1. 简单理解,一次脏检查就是调用一次 $apply() 或者 $digest(),将数据中最新的值呈现在界面上。
  2. 而每次 UI 事件变更,ajax 还有 timeout 都会触发 $apply()。

然而就有了接下来的讨论?

不断触发脏检查是不是一种好的方式?
 有很多人认为,这样对性能的损耗很大,不如 setter 和 getter 的观察者模式。 但是我们看下面这个例子

<span>{{checkedItemsNumber}}</span>
</div>
function Ctrl($scope){
 var list = [];
 $scope.checkedItemsNumber = 0;
 for(var i = 0;i<1000;i++){
 list.push(false);
 } 
 $scope.toggleChecked = function(flag){
 for(var i = 0,l= list.length;i++){
  list[i] = flag;
  $scope.checkedItemsNumber++;
 }
 }
}
</div>

在脏检测的机制下,这个过程毫无压力,会等待到 循环执行结束,然后一次更新 checkedItemsNumber,应用到界面上。 但是在基于setter的机制就惨了,每变化一次checkedItemsNumber就需要更新一次,这样性能就会极低。
 所以说,两种不同的监控方式,各有其优缺点,最好的办法是了解各自使用方式的差异,考虑出它们性能的差异所在,在不同的业务场景中,避开最容易造成性能瓶颈的用法。

好了,现在已经了解了双向数据绑定了 脏检查的触发机制,那么,脏检查内部又是怎么实现的呢?

脏检查的内部实现

首先,构造$scope 对象,

function $scope = function(){}
</div>

现在,我们回到开头 $watch。

我们说,每一个绑定到UI上的数据都有拥有一个对应的$watch 对象,这个对象会被push到watchList中。

它拥有两个函数作为属性

  1. getNewValue() 也叫监控函数,勇于在值发生变化后得到提示,并返回新值。
  2. listener() 监听函数,用于在数据变更的时候响应行为。

还有一个字符串属性

name: 当前watch作用的变量名

function $scope(){
 this. $$watchList = [];
}
</div>

在Angular框架中,双美元符前缀$$表示这个变量被当作私有的来考虑,不应当在外部代码中调用。

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • AngularJS的脏检查深入分析

相关文章

  • 2017-05-11JavaScript实现实时更新系统时间的实例代码
  • 2017-05-11layer弹出层框架alert与msg详解
  • 2017-05-11AngularJS表单基本操作
  • 2017-05-11D3.js中强制异步文件读取同步的几种方法
  • 2017-08-26前端Js框架汇总
  • 2017-05-11js和jquery中获取非行间样式
  • 2017-05-11Bootstarp 基础教程之表单部分实例代码
  • 2017-05-11nodejs中向HTTP响应传送进程的输出
  • 2017-05-11走进javascript——不起眼的基础,值和分号
  • 2017-05-11初探nodeJS

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • JS实现的添加弹出层并完成锁屏操作示例
    • setTimeout学习小结
    • JavaScript BASE64算法实现(完美解决中文乱码)
    • jQuery实现的简单排序功能示例【冒泡排序】
    • Angular.JS利用ng-disabled属性和ng-model实现禁用button效果
    • jQuery实现优雅的弹窗效果(6)
    • 在js代码拼接dom对象到页面上去的模板总结(必看)
    • js实现旋转木马效果
    • 详解微信小程序入门五: wxml文件引用、模版、生命周期
    • Bootstrap导航条学习使用(二)

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有