性能优化

zfh大约 4 分钟约 1123 字...

前端性能优化有哪些方式

综合性问题,待深挖

原则

多使用内存、缓存

减少 CPU 计算量,减少网络加载耗时 空间换时间

加载更快

  1. 减少资源体积:压缩代码
  2. 减少访问次数:合并代码、SSR 服务端渲染、缓存
  3. 使用更快的网络:CDN

渲染更快

为什么 css 放在 head,js 放在 body 最下面

希望在 DOM 树生成前就将 css 加载完,当 DOM 树加载完之后结合 CSSOM 树一次生成渲染树,一步完成渲染

js 可能会修改 DOM 结构

  1. css 放在 head,js 放在 body 最下面
  2. 尽早开始执行 js,用 DOMContentLoaded 触发
  3. 懒加载(图片懒加载,上滑加载更多,虚拟列表)
  4. 对 DOM 查询进行缓存 ?
  5. 频繁 DOM 操作,合并到一起插入 DOM 结构
  6. 节流防抖

讲一下浏览器渲染优化

针对 javaSCript

js 的加载会阻塞页面的渲染,

  1. 尽量将 javaSript 放在 body 的最后
  2. body 中间尽量不要写 script 标签
  3. 使用 async、defer 异步加载执行脚本

针对 css

使用 css 的三种方式:link、@import、内联样式、其中 link 和@import 都是导入外部样式,它们之间的区别:

  • link:浏览器会派发一个新的线程(HTTP 线程)去加载资源文件,与此同时 GUI 渲染线程会继续向下渲染代码
  • @import:GUI 渲染线程会暂时停止渲染,去服务器加载资源文件,资源文件没有返回之前不会继续渲染
  • style:GUI 直接渲染

外部样式如果长时间没有加载完毕,浏览器为了用户体验,会使用浏览器的默认样式,确保首次渲染速度,所以 css 一般写在 header 中,让浏览器尽快发送请求去获取 css 样式

所以在开发过程中,导入外部样式使用 link,而不用@import,如果 css 少,尽可能采用内嵌样式,直接写在 style 标签中

针对 DOM 树、CSSOM 树

可以通过一下方式来减少渲染的时间:

  • html 文件的代码层级尽量不要太深
  • 使用语义化的标签,来避免不标准语义化的特殊处理
  • 减少 css 的代码层级,因为选择器是从左到右进行解析的

减少回流和重绘

  • 操作 DOM 时,尽量在低层级的 DOM 节点进行操作
  • 不要使用 table 布局, 一个小的改动可能会使整个 table 进行重新布局
  • 不要频繁操作元素的样式,对于静态页面,可以修改类名,而不是样式
  • 使用 absolute 或者 fixed,使元素脱离文档流,这样他们发生变化就不会影响其他元素
  • 避免频繁操作 DOM,可以创建一个文档片段 documentFragment,在它上面应用所有 DOM 操作,最后再把它添加到文档中
  • 将元素先设置 display: none,操作结束后再把它显示出来。因为在 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘
  • 将 DOM 的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机制

手写防抖

防抖就类似回城,打断就得重新回

在事件被触发 n 秒后再执行回调,如果在这 n 秒内又被触发,则重新计时

场景:

  • search 搜索联想,用户在不断输入值时,用防抖来节约请求资源
  • window 触发 resize 的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次
function debouce(fn, delay = 500) {
  let timer = null
  return function () {
    if (timer) clearTimeout(timer)
    timer = setTimeout(() => {
      fn.apply(this, arguments)
    }, delay)
  }
}

手写节流

节流就类似技能需要冷却时间到了才能用

规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效

场景:

  • 鼠标不断点击触发,mousedown(单位时间内只触发一次)
  • 监听滚动事件,比如是否滑到底部自动加载更多,用 throttle 来判断
function throottle(fn, delay = 500) {
  let timer = null
  return function () {
    if (timer) return
    timer = setTimeout(() => {
      fn.apply(this, arguments)
      timer = null
    }, delay)
  }
}
上次编辑于:
本站勉强运行 小时
本站总访问量
網站計數器