angular常见问题总结

本文深入探讨AngularJS中的脏检查机制,解释其工作原理、触发条件及应用场景,帮助开发者理解如何有效利用这一机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文引自:https://www.cnblogs.com/zhoulujun/p/8881414.html

这篇是对angularJS的一些疑点回顾,是对目前angularJS开发的各种常见问题的整理汇总。如果对文中的题目全部了然于胸,觉得对整个angular框架应该掌握的七七八八了。希望志同道合的通知补充内容

Angular 的数据绑定采用什么机制,详述原理?

脏检查机制。阐释脏检查机制,必须先了解如下问题。

单向绑定(ng-bind) 和 双向绑定(ng-model) 的区别?

ng-bind 单向数据绑定($scope -> view),用于数据显示,简写形式是 {{}}。

两者的区别在于页面没有加载完毕 {{val}} 会直接显示到页面,直到 Angular 渲染该绑定数据(这种行为有可能将 {{val}} 让用户看到);而 ng-bind 则是在 Angular 渲染完毕后将数据显示。

ng-model 是双向数据绑定(scope>viewandview>scope−>viewandview−>scope),用于绑定值会变化的表单元素等。

双向数据绑定是 AngularJS 的核心机制之一。当 view 中有任何数据变化时,会更新到 model ,当 model 中数据有变化时,view 也会同步更新,显然,这需要一个监控。

 

双向数据绑定的原理?

Angular 在 scope 模型上设置了一个 监听队列,用来监听数据变化并更新 view 。

   每次绑定一个东西到 view 上时 AngularJS 就会往 watchwatch队列里插入一条watch,用来检测它监视的 model 里是否有变化的东西。    

当你写下表达式如{{ val }}时,AngularJS在幕后会为你在scope模型上设置一个watcher(表达式将被 Angular 编译成一个监视函数),它用来在数据发生变化的时候更新view。这里的watcher和你会在AngularJS中设置的watcher是一样的:

1
2
3
$scope.$watch( 'val' function (newValue, oldValue) {
   //update the DOM with newValue
});
  • 将数据附加到 Scope 上,数据自身不会对性能产生影响,如果没有监视器来监视这个属性,那个这个属性在不在 Scope 上是无关重要的;Angular 并不会遍历 Scope 上的属性,它将遍历所有的观察器。

  • 每个监视函数是在每次 $digest 过程中被调用的。因此,我们要注意观察器的数量以及每个监视函数或者监视表达式的性能。

 

 

$digest循环是在什么时候以各种方式开始的?

当浏览器接收到可以被 angular context 处理的事件时,digestdigest循环就会触发,遍历所有的watch,最后更新 dom。

举个栗子

1
< button  ng-click="val=val+1">increase 1</ button >

click 时会产生一次更新的操作(至少触发两次 $digest 循环)

  • 按下按钮

  • 浏览器接收到一个事件,进入到 angular context

  • digestdigest循环开始执行,查询每个watch 是否变化

  • 由于监视 scope.valscope.val的watch 报告了变化,因此强制再执行一次 $digest 循环

  • 新的 $digest 循环未检测到变化

  • 浏览器拿回控制器,更新 $scope. val.新值对应的 dom

 

在调用了scope.scope.digest()后,digestngclickhandlerscopeAngularJSdigest循环就开始了。假设你在一个ng−click指令对应的handler函数中更改了scope中的一条数据,此时AngularJS会自动地通过调用digest()来触发一轮digestdigest循环。当digest循环开始后,它会触发每个watcher。这些watchers会检查scope中的当前model值是否和上一次计算得到的model值不同。如果不同,那么对应的回调函数会被执行。调用该函数的结果,就是view中的表达式内容(译注:诸如{{ val }})会被更新。除了ng-click指令,还有一些其它的built-in指令以及服务来让你更改models(比如ng-model,timeout)timeout等)和自动触发一次digest循环。

目前为止还不错!但是,有一个小问题。在上面的例子中,AngularJS并不直接调用digest()digest(),而是调用scope.apply()apply(),后者会调用rootScope.$digest()。因此,一轮digestdigest循环在rootScope开始,随后会访问到所有的children scope中的watchers。

通常写代码时我们无需主动调用 applyapply或digest 是因为 angular 在外部对我们的回调函数做了包装。例如常用的 ng-click,这是一个指令(Directive),内部实现则 类似 于

1
2
3
DOM.addEventListener( 'click' function  ($scope) {
   $scope.$apply(() => userCode());
});

可以看到:ng-click 帮我们做了 applyapply这个操作。类似的不只是这些事件回调函数,还有http、timeoutangularServicetimeout等。我听很多人抱怨说angular这个库太大了什么都管,其实你可以不用它自带的这些服务(Service),只要你记得手工调用scope.$apply。

现在,假设你将ng-click指令关联到了一个button上,并传入了一个function名到ng-click上。当该button被点击时,AngularJS会将此function包装到一个wrapping function中,然后传入到scope.scope.apply()。因此,你的function会正常被执行,修改models(如果需要的话),此时一轮$digest循环也会被触发,用来确保view也会被更新。

 

Note: scope.scope.apply()会自动地调用rootScope.rootScope.digest()。apply()functionfunctionapply()方法有两种形式。第一种会接受一个function作为参数,执行该function并且触发一轮digest循环。第二种会不接受任何参数,只是触发一轮$digest循环。我们马上会看到为什么第一种形式更好。

 

$digest 循环会运行多少次?

$digest 循环的上限是 10 次(超过 10次后抛出一个异常,防止无限循环)。

$digest 循环不会只运行一次。在当前的一次循环结束后,它会再执行一次循环用来检查是否有 models 发生了变化。

这就是脏检查(Dirty Checking),它用来处理在 listener 函数被执行时可能引起的 model 变化。因此 digestmodeldigest循环会持续运行直到model不再发生变化,或者digest 循环的次数达到了 10 次(超过 10 次后抛出一个异常,防止无限循环)。

当 $digest 循环结束时,DOM 相应地变化。

脏检查如何被触发?

angular 会在可能触发 UI 变更的时候进行脏检查:这句话并不准确。实际上,

脏检查是digest执行的,另一个更常用的用于触发脏检查的函数apply——其实就是 $digest 的一个简单封装(还做了一些抓异常的工作)。

通常写代码时我们无需主动调用 applyapply或digest 是因为 angular 在外部对我们的回调函数做了包装。例如常用的 ng-click,这是一个指令(Directive),内部实现则 类似于

1
2
3
DOM.addEventListener( 'click' function  ($scope) {
   $scope.$apply(() => userCode());
});

angular对常用的dom事件,xhq事件作了封装,如果调用这些封装,就会在里面触发进入angular的digest流程,主要有以下情况:

  • DOM事件,如用户输入文本,点击按钮等,(ng-click)

  • XHQ响应事件($http)

  • 浏览器Location变更事件,即Url中hash部分变更($location)

  • Timer事件(Timeout,Timeout,interval)

  • 手动调用applyapply或digest

 

apply()apply()和digest() 的区别?

 

applyapply是scope(或者是 direcvie 里的 link 函数中的 scope)的一个函数,调用它会强制一次 digestdigest循环(除非当前正在执行循环,这种情况下会抛出一个异常,这是我们不需要在那里执行apply 的标志)。

apply()apply()和digest() 有两个区别。

  • 1) 最直接的差异是, $apply 可以带参数,它可以接受一个函数,然后在应用数据之后,调用这个函数。所以,一般在集成非 Angular 框架(比如jQuery)的代码时,可以把代码写在这个里面调用。

  • 2) 当调用 digestdigest的时候,只触发当前作用域和它的子作用域上的监控,但是当调用apply 的时候,会触发作用域树上的所有监控。

什么时候手动调用 $apply() 方法?

取决于是否在 Angular 上下文环境(angular context)。

AngularJS对此有着非常明确的要求,就是它只负责对发生于AngularJS上下文环境中的变更会做出自动地响应(即,在apply()models)AngularJSbuiltinmodelviewAngularJSmodel

转载于:https://www.cnblogs.com/x-jingxin/p/9469053.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值