前端性能优化
performance工具介绍
performance使用步骤
- 打开浏览器输入目标网址
- 进入开发人员工具面板,选择性能
- 开启录制功能,访问具体界面
- 执行用户行为,一段时间后停止录制
- 分析界面中记录的内存信息
内存问题的体现
内存问题的外在表现
- 页面出现延迟加载或者经常性暂停(代码中存在瞬间沾满内存-频繁进行垃圾回收)
- 页面持续性出现糟糕的性能(内存出现膨胀-页面为了达到最佳的速度,会申请一部分的内存空间,但是内存的空间的大小远超了设备提供的内存)
- 页面的性能随时间延长越来越差(内存的泄露-使内存空间越来越少)
监控内存的几种方式
界定内存问题的标准
- 内存泄漏:内存使用持续升高
- 内存膨胀:在多数设备上都存在性能问题(通过不同的设备测试发现都存在)
- 频繁垃圾回收:通过内存变化图进行分析 监控内存几种方式
- 浏览器任务管理器
- Timeline时序图记录
- 浏览器中堆快照查找分离DOM(内存泄漏)
- 判断是否存在频繁的垃圾回收
任务管理器监控内存
shift+esc调出任务管理器
Timeline记录内存
堆快照查找分离DOM
什么是分离DOM
- 界面元素存活在DOM树上
- 垃圾对象时的DOM节点(节点在DOM树上进行了脱离并且js代码中没有进行引用)
- 分离状态的DOM节点(节点在DOM树上进行了脱离但在js代码中进行引用,在页面上是看不见的,但是在内存上占据空间的说明存在内存泄漏)
判断是否存在频繁GC(垃圾回收)操作
为什么确定频繁垃圾回收
- GC工作时应用程序是停止的
- 频繁且过长的GC会导致应用假死
- 用户使用中感知应用卡顿
确定频繁的垃圾回收
- Timeline中频繁的上升下降(如果发现蓝色的走势条一直往上然后瞬间往下,在很短的时间内重复上述操作)
- 任务管理器中数据频繁的增加减小(正常情况下dom内存和JavaScript内存都是不变化的或者变化很小,如果有频繁的垃圾回收时,值就会瞬间增大,瞬间减小,重复操作)
代码优化
JSBench使用(jsbench.me)
慎用全局变量
- 全局变量定义在全局执行上下文,是所有作用域链的顶端
- 全局执行上下文一直存在于上下文执行栈,直到程序退出,消耗内存
- 如果某个局部作用域出现了同名变量则会遮蔽或者污染全局
缓存全局变量
将使用中无法避免的全局变量缓存到局部
通过原型对象添加附加方法
构造函数、原型对象、实例对象;构造函数和实例对象都可以指向原型对象的,如果某个构造函数内部的成员方法,让后面的实例对象进行频繁的调用,所以我们需要在原型对象上新增实现对象需要的方法
将方法放在原型对象上和构造函数中进行对比
避开闭包陷阱
闭包使用不当很容易出现内存泄漏
避免属性访问方法使用
选择最优的循环方法
foreach>for>forin
节点添加优化(文档碎片)
createDocumentFragment
减少判断层级(易于维护的代码不代表执行速度快)
如果代码中出现多层if-else嵌套的时候,可考虑是否通过提前return的方式,减少嵌套层级,如果发现嵌套中出现大量的else if并且esle if中的值是固定的,则建议使用switch case
减少作用域链查找层级
每个函数执行时都会产生执行上下文,定义执行的函数环境,当函数执行完成后执行上下文就会被销毁(取决于是否存在闭包),多次调用同一个函数的时候,就会创建多个执行上下文,并且每个上下文都有自己的作用域的,这些作用域之间又可以通过作用域链连接,在函数执行的过程中,每遇到一个变量就会先去搜索自己内部的作用域,如果发现没有就会通过作用域链向上查找(父作用域),如果还没有找到就会进行向上找
减少数据读取次数
对象数据有时会在原型链上查找,就需要减少对象查找的次数和属性的嵌套层级——提前将对象的数据进行缓存
字面量与构造式
引用数据类型的字面量和构造式声明差距不大,但基本数据类型字面量和构造式声明差距就非常大
构造式相当于创建了一个对象,好处就是可以通过原型链直接调用原型链上的方法,字面量声明基本数据类型,在使用一些方法时,是先默认的转换对象,在调用其内部方法,如果没转也是会是对象下的实例,也可以通过原型链找到;
字面量比构造式声明会少占空间,使用构造式声明,需要多余的空间存放obj上面的属性和方法
减少循环体活动(可加快运行时间)
- 尽可能的将循环体中重复的事情(数据值不变的值)提出出来,在循环体外处理
- 采用从后往前遍历,代码量可以减少,减少条件判断,增快循环速度
减少声明及语句数
- 不是频繁使用的数据建议直接获取而不是提前进行缓存,降低程序在使用时对内存的消耗
- 最小化语句数(表达式)
采用事件绑定(事件委托)
DOM操作使用事件委托——利用js事件冒泡机制,把原本需要绑定在子元素的事件委托给了父元素进行监听,可以大量减少内存的占用和事件的注册