搜索
首页web前端js教程angular如何进行性能优化?变更检测方式浅析

angular如何进行性能优化?下面本篇文章给大家深入介绍一下angular 性能优化方案--变更检测,希望对大家有所帮助!

angular如何进行性能优化?变更检测方式浅析

angular 性能优化——变更检测

         对于前端性能指标描述,业界都各有说词,总结下来都和首屏性能和页面流畅度相关, 本次将会从页面流畅度的角度,对页面交互性能优化进行分析。【相关教程推荐:《angular教程》】

什么是页面流畅度?

        页面流畅度是通过帧率 FPS(Frames Per Second - 每秒传输帧数)判定的,一般主流的浏览器屏幕刷新率都在 60Hz(每秒刷新60次),最优的帧率在 60 FPS,帧率越高,页面就越流畅,60Hz意味着每隔16.6ms会刷新一次显示屏,也就是每一次渲染页面需要在16.6ms内完成,否则就会导致页面失帧,出现卡顿现象。根因在于:浏览器中的 JavaScript 执行和页面渲染会相互阻塞

         在 Chrome 的 devtools 中我们可以执行 Cmd+Shift+P 输入 show fps 来快速打开 fps 面板,如下图所示:

1.png

通过观察 FPS 面板,我们可以很方便的对当前页面的流畅度进行监控

2.png

1 影响页面性能的因素

         页面交互是否流畅,在于页面响应是否流畅,而页面响应其本质上就是把页面状态的变更重新渲染到页面上的过程。

         页面响应过程大致如下:

3.png

一般情况Event Handler事件处理逻辑不会消耗太多时间,所以影响angular性能的因素主要在于异步事件触发变更检测。 一般情况Event Handler事件处理逻辑不会消耗太多时间,所以影响angular性能的因素主要在于异步事件触发和变更检测。

         对angular来说,页面渲染的过程就是变更检测的过程,可以理解为angular的变更检测要在16.6ms内完成才不会导致页面失帧、卡顿。

可以从以下三方面优化页面响应的性能。

(1)对于触发事件阶段,可以减少异步事件的触发,来减少整体的变更检测次数和重新渲染;  

(2)对于 Event Handler 执行逻辑阶段,可以通过优化复杂代码逻辑来减少执行时间;

(3)对于 Change Detection 检测数据绑定并更新 DOM 阶段,可以减少变更检测模板数据的计算次数来减少渲染时间;

对于(2)Event Handler要具体问题具体分析,不做讨论,主要针对(1)(3)进行优化

2 优化方案

2.1 减少异步事件触发

         Angular在默认变更检测模式下,异步事件会触发全局的变更检测,因此,减少异步事件的触发会大大的提升angular的性能。

         异步事件包括Macro Task(宏任务)事件和Micro Task微任务事件

4.png

         对异步事件的优化主要是针对document的监听事件。比如document上的click、mouseup、mousemove…等监听事件。

         监听事件场景:

                Renderer2.listen(document, …)

                fromEvent(document,…)

                document.addEventListener(…)

         dom监听事件,在不需要触发的时候一定要移除。

举例:[pop]提示框指令

         使用场景:表格列筛选,点击图标以外的地方,或者页面滚动,列筛选弹框隐藏

         以前的做法是直接在pop指令里监听document的click事件和scroll事件,这样有个弊端就是提示框未显示,但依然存在监听事件,很不合理。

         合理的解决方案:当提示框显示的时候才去监听click和scroll事件,隐藏的时候就移除监听事件。

5.png

对于频繁触发的dom监听事件,可以使用rjx的操作符对事件进行优化。详情参考Rjx操作符RxJS Marbles

2.2 变更检测

什么是变更检测?

         要理解变更检测,我们可以从变更检测的目标寻找答案。angular变更检测目标,是让模型(TypeScript代码)与模板(HTML)保持同步。因此,变更检测可以理解为:检测模型变更的同时,更新模板( DOM

变更检测流程是什么?

6.png

       通过在组件树中按照自顶向下的顺序执行变更检测,也就是先对父组件执行变更检测,再对子组件进行变更检测。首先检查父组件的数据变更,然后更新父组件模板,在更新模板的时候遇到子组件,会去更新子组件上绑定的值,然后进入子组件,看@Input输入值的索引是否改变,如果改变就将该子组件标记为dirty,也就是后续需要变更检测的,标记完子组件之后,继续更新父组件中子组件后面的模板,父组件模板全部更新完之后再去对子组件做变更检测。

2.2.1 angular变更检测原理   

       在默认变更检测default模式下,异步事件触发Angular的变更检测的原理是 angular通过使用Zone.js处理异步事件时调用了ApplicationRef 的tick()方法从根组件到子组件执行变更检测。 Angular 应用初始化过程中,实例化了一个zone (NgZone),然后将所有逻辑都跑在该对象的 _inner 对象中。

Zone.js实现了以下几个类:

  • Zone类,JavaScript 事件的执行环境,和线程一样,它们可以带一些数据,并且可能拥有父子 zone。
  • ZoneTask类,包装后的异步事件,这些 task 有三种子类:
    • MicroTask,由 Promise 创建。
    • MacroTask,由 setTimeout 等创建。
    • EventTask,由 addEventListener 等创建,比如dom事件。
  • ZoneSpec对象,创建一个 ngZone 时给它提供的参数,有三个可以触发检测的钩子:
    • onInvoke,调用某个回调函数时触发的钩子。
    • onInvokeTask,ZoneTask 被触发时触发的钩子,比如 setTimeout 到时。
    • onHasTask,检测到有或无 ZoneTask 时触发的钩子(即对第一个 schedule 的 zone 和最后一个 invoke 或 cancel 的 task 触发)。
  • ZoneDelegate类,负责调用钩子。

检测过程原理大概如下:

       用户操作触发异步事件(比如:dom事件,接口请求…)

=>  ZoneTask类处理事件。invokeTask()函数中调用zone的runTask()方法,在runTask方法中,zone通过_zoneDelegate实例属性,调用ZoneSpec的钩子

=>  ZoneSpec的三个钩子(onInvokeTask、onInvoke、onHasTask)钩子里通过checkStable()函数触发zone.onMicrotaskEmpty.emit(null)通知

=>  根组件监听onMicrotaskEmpty后调用tick(),tick方法中调用 detectChanges()从根组件开始检测

=> ··· refreshView()调用executeTemplate()executeTemplate方法中调用templateFn()更新模板、子组件绑定的值(这时候会去检测子组件的@Input()输入引用是否改变,如果有改变,会将子组件标记为Dirty,也就是该子组件需要变更检测

详细变更检测原理流程图:

7.png

简化流程:

触发异步事件

=>  ZoneTask处理事件

=> ZoneDelegate 调用ZoneSpec的钩子触发onMicrotaskEmpty通知

=> 根组件收到onMicrotaskEmpty通知,执行tick(),开始检测并更新dom

8.png

由以上代码可知,当微任务为空的时候才会触发变更检测

简略变更检测原理流程图:

9.png

Angular 源码解析 Zone.js参考blog

2.2.2 变更检测优化方案

1 )使用OnPush 模式

原理:减少1次变更检测的耗时。

         OnPush模式与Default模式的区别在于:dom监听事件、timer事件、promise都不会触发变更检测。Default模式的组件状态始终为CheckAlways,表示组件每次检测周期都要检测。

OnPush模式下:以下情况会触发变更检测

    S1、组件的@Input引用发生变化。

    S2、组件的DOM绑定的事件,包括它子组件的DOM绑定的事件,比如 click、submit、mouse down。@HostListener()

      注意:

        通过renderer2.listen()监听的dom事件不会触发变更检测

        通过dom.addEventListener()原生监听方式也不会触发变更检测

    S3、Observable 订阅事件,同时设置 Async pipe。

    S4、利用以下方式手动触发变化检测:

      ChangeDetectorRef.detectChanges():触发当前组件和非OnPush子组件的变更检测。

      ChangeDetectorRef.markForCheck():将当前视图及其所有的祖先标记为脏,下次检测周期时候会触发检测。

      ApplicationRef.tick():不会触发变更检测

2 )使用NgZone.runOutsideAngular()

原理:减少变更检测次数

         将全局dom事件监听写在NgZone.runOutsideAngular()方法的回调里面,dom事件将不会触发angular的变更检测。如果当前组件未更新,可以在回调函数里执行ChangeDetectorRef的detectChanges()钩子来手动触发当前组件的变更检测。

举例:app-icon-react动态图标组件

10.png

2.2.3 调试方式

         方式1:可以在浏览器控制台,使用Angular DevTools插件查看某一次dom事件,angular的检测情况:

11.png

         方式2:可以在控制台直接输入:ng.profiler.timeChangeDetection()查看检测时间,这种方式可查看全局的检测时间。参考博客 Profiling Angular Change Detection

12.png

2.3 模板(HTML)优化

2.3.1 减少DOM渲染:ngFor加trackBy

         使用 *ngFor 的 trackBy 属性,Angular 只更改和重新渲染已更改的条目,而不必重新加载整个条目列表。

         比如:表格排序场景。ngFor如果加了trackBy,表格渲染的时候只会移动行dom元素,如果不加trackBy,会先删除现有的表格dom元素,再新增行dom元素。显然只移动dom元素性能会好很多。

2.3.2 模板表达式中不要使用函数

         不要在Angular 模板表达式中使用函数调用,可以用管道pipe代替,也可以通过手动计算后用一个变量代替。模板中使用函数,不管值有没有改变,每次变更检测的时候都会执行函数,会影响性能。

         模板中使用函数的场景:

13.png

2.3.3 减少ngFor的使用

使用ngFor,数据量大的时候会影响性能。

举例:

使用ngFor:

14.png

15.png

不使用ngFor:性能提升10倍左右

16.png

17.png

更多编程相关知识,请访问:编程视频!!

以上是angular如何进行性能优化?变更检测方式浅析的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文转载于:掘金社区。如有侵权,请联系admin@php.cn删除
Python vs. JavaScript:社区,图书馆和资源Python vs. JavaScript:社区,图书馆和资源Apr 15, 2025 am 12:16 AM

Python和JavaScript在社区、库和资源方面的对比各有优劣。1)Python社区友好,适合初学者,但前端开发资源不如JavaScript丰富。2)Python在数据科学和机器学习库方面强大,JavaScript则在前端开发库和框架上更胜一筹。3)两者的学习资源都丰富,但Python适合从官方文档开始,JavaScript则以MDNWebDocs为佳。选择应基于项目需求和个人兴趣。

从C/C到JavaScript:所有工作方式从C/C到JavaScript:所有工作方式Apr 14, 2025 am 12:05 AM

从C/C 转向JavaScript需要适应动态类型、垃圾回收和异步编程等特点。1)C/C 是静态类型语言,需手动管理内存,而JavaScript是动态类型,垃圾回收自动处理。2)C/C 需编译成机器码,JavaScript则为解释型语言。3)JavaScript引入闭包、原型链和Promise等概念,增强了灵活性和异步编程能力。

JavaScript引擎:比较实施JavaScript引擎:比较实施Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和执行JavaScript代码时,效果会有所不同,因为每个引擎的实现原理和优化策略各有差异。1.词法分析:将源码转换为词法单元。2.语法分析:生成抽象语法树。3.优化和编译:通过JIT编译器生成机器码。4.执行:运行机器码。V8引擎通过即时编译和隐藏类优化,SpiderMonkey使用类型推断系统,导致在相同代码上的性能表现不同。

超越浏览器:现实世界中的JavaScript超越浏览器:现实世界中的JavaScriptApr 12, 2025 am 12:06 AM

JavaScript在现实世界中的应用包括服务器端编程、移动应用开发和物联网控制:1.通过Node.js实现服务器端编程,适用于高并发请求处理。2.通过ReactNative进行移动应用开发,支持跨平台部署。3.通过Johnny-Five库用于物联网设备控制,适用于硬件交互。

使用Next.js(后端集成)构建多租户SaaS应用程序使用Next.js(后端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:23 AM

我使用您的日常技术工具构建了功能性的多租户SaaS应用程序(一个Edtech应用程序),您可以做同样的事情。 首先,什么是多租户SaaS应用程序? 多租户SaaS应用程序可让您从唱歌中为多个客户提供服务

如何使用Next.js(前端集成)构建多租户SaaS应用程序如何使用Next.js(前端集成)构建多租户SaaS应用程序Apr 11, 2025 am 08:22 AM

本文展示了与许可证确保的后端的前端集成,并使用Next.js构建功能性Edtech SaaS应用程序。 前端获取用户权限以控制UI的可见性并确保API要求遵守角色库

JavaScript:探索网络语言的多功能性JavaScript:探索网络语言的多功能性Apr 11, 2025 am 12:01 AM

JavaScript是现代Web开发的核心语言,因其多样性和灵活性而广泛应用。1)前端开发:通过DOM操作和现代框架(如React、Vue.js、Angular)构建动态网页和单页面应用。2)服务器端开发:Node.js利用非阻塞I/O模型处理高并发和实时应用。3)移动和桌面应用开发:通过ReactNative和Electron实现跨平台开发,提高开发效率。

JavaScript的演变:当前的趋势和未来前景JavaScript的演变:当前的趋势和未来前景Apr 10, 2025 am 09:33 AM

JavaScript的最新趋势包括TypeScript的崛起、现代框架和库的流行以及WebAssembly的应用。未来前景涵盖更强大的类型系统、服务器端JavaScript的发展、人工智能和机器学习的扩展以及物联网和边缘计算的潜力。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
4 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
4 周前By尊渡假赌尊渡假赌尊渡假赌
WWE 2K25:如何解锁Myrise中的所有内容
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

适用于 Eclipse 的 SAP NetWeaver 服务器适配器

将Eclipse与SAP NetWeaver应用服务器集成。

Dreamweaver Mac版

Dreamweaver Mac版

视觉化网页开发工具

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

MinGW - 适用于 Windows 的极简 GNU

MinGW - 适用于 Windows 的极简 GNU

这个项目正在迁移到osdn.net/projects/mingw的过程中,你可以继续在那里关注我们。MinGW:GNU编译器集合(GCC)的本地Windows移植版本,可自由分发的导入库和用于构建本地Windows应用程序的头文件;包括对MSVC运行时的扩展,以支持C99功能。MinGW的所有软件都可以在64位Windows平台上运行。