前端性能优化—代码层面

1,592 阅读6分钟

前端性能优化

performance工具介绍

performance使用步骤

  1. 打开浏览器输入目标网址
  2. 进入开发人员工具面板,选择性能
  3. 开启录制功能,访问具体界面
  4. 执行用户行为,一段时间后停止录制
  5. 分析界面中记录的内存信息

内存问题的体现

内存问题的外在表现

  1. 页面出现延迟加载或者经常性暂停(代码中存在瞬间沾满内存-频繁进行垃圾回收)
  2. 页面持续性出现糟糕的性能(内存出现膨胀-页面为了达到最佳的速度,会申请一部分的内存空间,但是内存的空间的大小远超了设备提供的内存)
  3. 页面的性能随时间延长越来越差(内存的泄露-使内存空间越来越少)

监控内存的几种方式

界定内存问题的标准

  1. 内存泄漏:内存使用持续升高
  2. 内存膨胀:在多数设备上都存在性能问题(通过不同的设备测试发现都存在)
  3. 频繁垃圾回收:通过内存变化图进行分析 监控内存几种方式
  4. 浏览器任务管理器
  5. Timeline时序图记录
  6. 浏览器中堆快照查找分离DOM(内存泄漏)
  7. 判断是否存在频繁的垃圾回收
任务管理器监控内存

shift+esc调出任务管理器 1.png

Timeline记录内存

2.png

堆快照查找分离DOM

什么是分离DOM

  1. 界面元素存活在DOM树上
  2. 垃圾对象时的DOM节点(节点在DOM树上进行了脱离并且js代码中没有进行引用)
  3. 分离状态的DOM节点(节点在DOM树上进行了脱离但在js代码中进行引用,在页面上是看不见的,但是在内存上占据空间的说明存在内存泄漏) 3.png 4.png
判断是否存在频繁GC(垃圾回收)操作

为什么确定频繁垃圾回收

  1. GC工作时应用程序是停止的
  2. 频繁且过长的GC会导致应用假死
  3. 用户使用中感知应用卡顿

确定频繁的垃圾回收

  1. Timeline中频繁的上升下降(如果发现蓝色的走势条一直往上然后瞬间往下,在很短的时间内重复上述操作)
  2. 任务管理器中数据频繁的增加减小(正常情况下dom内存和JavaScript内存都是不变化的或者变化很小,如果有频繁的垃圾回收时,值就会瞬间增大,瞬间减小,重复操作)

代码优化

JSBench使用(jsbench.me) 5.png

慎用全局变量

  1. 全局变量定义在全局执行上下文,是所有作用域链的顶端
  2. 全局执行上下文一直存在于上下文执行栈,直到程序退出,消耗内存
  3. 如果某个局部作用域出现了同名变量则会遮蔽或者污染全局

缓存全局变量

将使用中无法避免的全局变量缓存到局部

通过原型对象添加附加方法

构造函数、原型对象、实例对象;构造函数和实例对象都可以指向原型对象的,如果某个构造函数内部的成员方法,让后面的实例对象进行频繁的调用,所以我们需要在原型对象上新增实现对象需要的方法
将方法放在原型对象上和构造函数中进行对比 17.png

避开闭包陷阱

闭包使用不当很容易出现内存泄漏

避免属性访问方法使用

18.png

选择最优的循环方法

foreach>for>forin 19.jpg

节点添加优化(文档碎片)

createDocumentFragment 20.png 21.png

减少判断层级(易于维护的代码不代表执行速度快)

如果代码中出现多层if-else嵌套的时候,可考虑是否通过提前return的方式,减少嵌套层级,如果发现嵌套中出现大量的else if并且esle if中的值是固定的,则建议使用switch case 6.jpg

减少作用域链查找层级

每个函数执行时都会产生执行上下文,定义执行的函数环境,当函数执行完成后执行上下文就会被销毁(取决于是否存在闭包),多次调用同一个函数的时候,就会创建多个执行上下文,并且每个上下文都有自己的作用域的,这些作用域之间又可以通过作用域链连接,在函数执行的过程中,每遇到一个变量就会先去搜索自己内部的作用域,如果发现没有就会通过作用域链向上查找(父作用域),如果还没有找到就会进行向上找 7.png 8.png

减少数据读取次数

对象数据有时会在原型链上查找,就需要减少对象查找的次数和属性的嵌套层级——提前将对象的数据进行缓存 10.png 11.png 9.png

字面量与构造式

引用数据类型的字面量和构造式声明差距不大,但基本数据类型字面量和构造式声明差距就非常大 构造式相当于创建了一个对象,好处就是可以通过原型链直接调用原型链上的方法,字面量声明基本数据类型,在使用一些方法时,是先默认的转换对象,在调用其内部方法,如果没转也是会是对象下的实例,也可以通过原型链找到;
字面量比构造式声明会少占空间,使用构造式声明,需要多余的空间存放obj上面的属性和方法 12.jpg

减少循环体活动(可加快运行时间)

  1. 尽可能的将循环体中重复的事情(数据值不变的值)提出出来,在循环体外处理 13.png
  2. 采用从后往前遍历,代码量可以减少,减少条件判断,增快循环速度 14.png

减少声明及语句数

  1. 不是频繁使用的数据建议直接获取而不是提前进行缓存,降低程序在使用时对内存的消耗 15.png
  2. 最小化语句数(表达式) 16.png

采用事件绑定(事件委托)

DOM操作使用事件委托——利用js事件冒泡机制,把原本需要绑定在子元素的事件委托给了父元素进行监听,可以大量减少内存的占用和事件的注册