前端性能优化 常见面试题速查

2023-05-17 16:41:59 浏览数 (1)

# 懒加载

懒加载也叫延迟加载、按需加载,指在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。在比较长的网页或者应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可是窗口的哪一部分图片数据,对性能有浪费。

在滚动屏幕之前,可视区域之外的图片不会进行加载,在滚动屏幕时才加载。这样可以使网页的加载速度更快,减少了服务器的负载。懒加载适用于图片较多,页面列表较长的创建中。

# 特点

  • 减少无用资源的加载
    • 减少了服务器的压力和流量,同时减小浏览器的负担
  • 提升用户体验
    • 同时加载较多图片,可能需要等待的时间较长
  • 防止加载过多图片而影响其他资源文件的加载
    • 会影响网站应用的正常使用

# 实现原理

图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。根据这个原理,可以使用 HTML5 的 data-xx 属性来存储图片的地址,在需要加载的时候,将 data-xx 属性的值赋给 src 属性,就实现了图片的按需加载,即懒加载

使用原生 JavaScript 实现懒加载

  • 知识点
    • window.innerHeight 浏览器视口高度
    • document.documentElement.scrollTop 浏览器滚动过的距离
    • imgs.offsetTop 图片顶部距离文档底部的高度
  • 图片加载条件:imgs.offsetTop < window.innerHeight document.documentElement.scrollTop
代码语言:javascript复制
<div class="container">
  <img src="loading.gif" data-src="pic.png" />
  <img src="loading.gif" data-src="pic.png" />
  <img src="loading.gif" data-src="pic.png" />
  <img src="loading.gif" data-src="pic.png" />
  <img src="loading.gif" data-src="pic.png" />
  <img src="loading.gif" data-src="pic.png" />
</div>
<script>
  var imgs = document.querySelectorAll('img');
  function lazyLoad () {
    var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
    var winHeight = window.innerHeight;
    for (var i = 0; i < imgs.length; i  ) {
      var img = imgs[i];
      if (img.offsetTop < scrollTop   winHeight) {
        img.src = img.getAttribute('data-src');
      }
    }
  }
  window.addEventListener('scroll', lazyLoad);
</script>

# 回流与重绘

# 回流

当渲染树中部分或者全部元素的尺寸、结构或者属性发生变化时,浏览器会重新渲染部分或者全部文档的过程即回流

可能会导致回流的操作有:

  • 页面的首次渲染
  • 浏览器窗口大小发生变化
  • 元素的内容发生变化
  • 元素的尺寸或者位置发生变化
  • 元素的字体大小发生变化
  • 激活 CSS 伪类
  • 查询某些属性或者调用某些方法
  • 添加或者删除可见的 DOM 元素

在触发回流(重排)时,由于浏览器渲染页面是基于流式布局的,所以当触发回流时,会导致周围的 DOM 元素重新排列,它的影响范围有两种:

  • 全局范围:从根节点开始,对整个渲染树进行重新布局
  • 局部范围:对渲染树的某部分或者一个渲染对象进行重新布局

# 重绘

当页面中某些元素的样式发生变化,但是不会影响其在文档流中的位置时,浏览器就会对元素进行重新绘制,即重绘

可能导致重绘的操作有:

  • colorbackground 相关属性:background-colorbackground-image
  • outline 相关属性:outline-coloroutline-widthtext-decorationborder-radiusvisibilitybox-shadow

注意:当触发回流时,一定会触发重绘,但是重绘不一定引发回流

# 如何避免回流和重绘

  • 减少回流与重绘的措施
    • 操作 DOM 时,尽量在低层级的 DOM 节点进行操作
    • 不要使用 table 布局,一个小的改动可能会使整个 table 进行重新布局
    • 使用 CSS 的表达式,不要频繁操作元素的样式,对于静态页面,可以修改类名,而不是样式
    • 使用 absolutefixed 使元素脱离文档流,这样他们发生变化就不会影响其他元素
    • 避免频繁操作 DOM,可以创建一个文档片段 documentFragment,然后把需要操作的元素添加到文档片段中,在片段中进行 DOM 操作,最后一起插入到文档中
    • 将元素设置为 display: none,进行操作结束后再把它显示出来,因为 display 属性为 none 的元素上进行的 DOM 操作不会引发回流和重绘
    • 将 DOM 的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写,这得益于浏览器的渲染队列机制
      • 浏览器针对页面的回流与重绘,使用渲染队列进行了自身的优化
      • 浏览器会将所有的回流、重绘的操作放到一个队列中,当队列中的操作到了一定的数量或者到达一定的时间间隔,浏览器就会对队列进行批处理,这会让多次的回流、重绘合并成一次

# 如何优化动画

通常,动画需要频繁地操作 DOM,就会导致页面的性能问题。可以将动画的 position 属性设置为 absolutefixed,将动画脱离文档流,这样他的回流就不会影响页面了。

# documentFragment

DocumentFragment 文档片段接口,一个没有父亲对象的最小文档对象。它被作为一个轻量版的 Document 使用,就像标准的 document 一样,存储由节点(nodes)组成的文档结构。与 document 相比,最大的区别是 DocumentFragment 不是真是 DOM 树的一部分,它的变化不会触发 DOM 树的重新渲染,且不会导致性能问题。

当我们把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。在频繁的 DOM 操作时,就可以将 DOM 元素插入 DocumentFragment,之后一次性地将所有的子孙节点插入文档中。和直接操作 DOM 相比,将 DocumentFragment 节点插入 DOM 树时,不会触发页面的重绘,大大提高了页面的性能。

0 人点赞