angular 变更检测,angular 调试
什么是变化检测?下面这篇文章带你了解Angular中的变化检测机制,讲述变化检测是如何工作的,并介绍角度变化检测的性能优化方法,希望对你有所帮助!
什么是变更检测(Change Detection)?
变更检测的概念
组件中的数据状态更改后,视图需要相应地更新。这种同步视图和数据的机制称为变化检测。【相关教程推荐:《angular教程》】
变更检测的触发时机
只要有异步操作(事件、定时器、XHR)发生,Angular就会认为状态可能发生了变化,然后会进行变化检测。
事件:click、mouseover、mouseout、keyup、keydown等浏览器事件;timer:setTimeout/setInterval;XHR:各种各样的请求,等等。既然所有的异步操作都要接受变更检测,那么Angular是如何订阅变更检测的异步请求的呢?
这里,我们来介绍一下NgZone及其fork对象Zone.js
Zone.js用于封装和拦截浏览器中的异步活动。还提供异步生命周期的钩子和统一的异步错误处理机制。。
Zone.js通过猴子打补丁的方式拦截浏览器中常见的方法和元素,比如setTimeout和html element . prototype . onclick Angular会在启动时使用Zone.js打几个底层浏览器API的补丁,从而捕获异步事件,并在捕获时间过后调用变化检测。
Angular通过forkZone.js扩展了自己的zone NgZone,这样应用中所有的异步操作都会在这个zone中运行。
Angular的变更检测如何工作的?
Angualr将为每个组件生成一个changeDetector,以记录组件的更改状态。
在我们创建一个Angular应用程序之后,Angular还将创建一个ApplicationRef的实例,它表示我们当前创建的Angular应用程序的实例。创建ApplicationRef时,会订阅ngZone中的onMicrotaskEmpty事件,并在所有微任务完成后调用所有视图的detectChanges()进行变化检测。
变更检测的执行顺序
更新所有子组件绑定的属性。
调用所有子组件生命周期的hooks OnChanges,OnInit,DoCheck,AfterContentInit。
更新当前组件的DOM
调用子组件的变更检测。
调用所有子组件的生命周期钩子ngAfterViewInit。
以栗子为例。在开发模式时,我们可能会遇到这种错误:
这是因为变化检测遵循从根组件开始,从上到下执行每个组件的变化检测,直到最后一个组件达到稳定状态。在下一次变更检测之前,不允许子代和孙代修改父组件中的属性。
情况1在开发模式下,Angular将执行二次检测(在生产环境中调用enableProdMode()时,检测次数将减少到1)。一旦我们在步骤4完成后修改了后代组件中父组件的属性,那么Angular进行第二次测试时,发现两个值不一致,就会出现上面的错误。
情况2只要父组件绑定了子组件的属性,那么无论下面的代码在OnChanges、OnInit、DoCheck、AfterContentInit、AfterViewInit的任何一个生命周期钩子中执行,都会报错。
//#parent
{{data}}
child [data]=data/child
//在子组件ts中,执行:
this.parent.data=新值;
变更检测的执行策略
Default 策略
每次事件触发变化检测(如用户事件、定时器、XHR、承诺等。),这个默认策略将从上到下检查组件树中的每个组件。这种在不做任何假设的情况下检查组件依赖性的保守方法被称为脏检查。当我们应用太多组件时,这种策略会影响应用程序的性能。
OnPush 策略
在修改了组件装饰器的changeDetection并将其设置为OnPush策略后,Angular将在每次触发变更检测时跳过该组件及其所有子组件的变更检测。
根据OnPush策略,只有以下情况才会触发组件的更改检测:
输入值(@Input)更改(输入的值必须是新的引用)当前组件或子组件之一触发了事件(但在onPush策略中,下面的操作不会触发变化检测)SetTimeOut()SetInterval()Promise。解决()。然后()This.http.get( . ).Subscribe ()手动触发变更检测(每个组件将与一个组件视图ChangeDetectorRef相关联)detectChanges():它将触发当前组件和子组件的更改检测markForCheck():。不会触发变更检测,但会检测当前on-push组件以及当前或下一个变更检测周期标记为需要检测状态内父组件为on-pushApplicationRef.tick()的所有组件:会根据组件的变更检测策略。触发整个应用程序的变化检测async pipe
对于Angular的变更检测如何优化?
由于组件默认实现默认策略,任何异步操作都会触发对整个组件号的自顶向下的检查。即使Angular团队不断提升性能,可以在毫秒级完成数百次检测,但当应用扩展到数百个组件时,庞大的组件树对应的变化检测就会达到性能瓶颈。
此时,我们需要开始分析,减少不必要的测试。
如何减少检测次数
区域污染(Zone Pollution)
一般我们在生命周期钩子中使用第三方库比如chart类库进行初始化,会带来RequestAnimationRequest/SetTimeout/addevent listener。我们可以将初始化方法写入NgZone的runOutsideAngular方法中。
OnPush 策略
对于不涉及更新操作的视图,您可以剥离组件,并使用onPush策略通过通知更新来刷新视图(参见上面的变更检测的执行策略部分)。
用 pure pipe 代替 {{function(data)}}
在html文件中,写入{{function(data)}}将导致每次发生更改检测时重新计算所有值。(?当有一个1000项的列表时,您只修改一项数据,但其他999项不需要更新的数据将重新计算。)
此时,我们可以使用管道方法,只有更改后的值才会触发操作并更新一些视图。
面对大量数据的渲染,选择虚拟滚动/分页请求数据
以上四种解决方案来自Angular team的视频介绍。视频中利用Angular devtool的运算次数来分析和解决问题。所以,如果你的Angular是9,请继续读下去,如何安装和运行Angular devtool。
插件:Angular devtool使用介绍
Angular 9,支持常春藤。并引导和下载地址,确保运行环境是开发环境//environment.dev.ts。
.
生产:假
.angular.json dev配置项“优化”:false项目your-project-name architect构建配置dev“优化”:false有关编程的更多信息,请访问:编程教学!以上是对角度变化检测机制的分析,并谈谈如何优化性能。更多详情请关注我们的其他相关文章!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。