前端性能优化篇

1. 重排优化

减少重排范围

  • 尽可能在低层级的DOM节点上,而不是像上述全局范围的示例代码一样,如果你要改变p的样式,class就不要加在div上,通过父元素去影响子元素不好。

  • 不要使用 table 布局,可能很小的一个小改动会造成整个 table 的重新布局。那么在不得已使用table的场合,可以设置table-layout:auto;或者是table-layout:fixed这样可以让table一行一行的渲染,这种做法也是为了限制reflow的影响范围。

减少重排次数

  • 1.样式集中改变

    • 不要频繁的操作样式,对于一个静态页面来说,明智且可维护的做法是更改类名而不是修改样式,对于动态改变的样式来说,相较每次微小修改都直接触及元素,更好的办法是统一在 cssText 变量中编辑。
  • 2.分离读写操作

    • DOM 的多个读操作(或多个写操作),应该放在一起。不要两个读操作之间,加入一个写操作。
  • 3.将 DOM 离线

    • 使用 display:none(后面再显示,总共触发两次重排)
    • 通过 documentFragment 创建一个 dom 碎片,在它上面批量操作 dom,操作完成之后,再添加到文档中,这样只会触发一次重排。
    • 复制节点,在副本上工作,然后替换它!
  • 4.使用 absolute 或 fixed 脱离文档流

  • 5.优化动画

    • 可以把动画效果应用到 position属性为 absolute 或 fixed 的元素上,这样对其他元素影响较小。
    • 启用GPU加速 GPU 硬件加速是指应用 GPU 的图形性能对浏览器中的一些图形操作交给 GPU 来完成,因为 GPU 是专门为处理图形而设计,所以它在速度和能耗上更有效率。
      • GPU 加速通常包括以下几个部分:Canvas2D,布局合成, CSS3转换(transitions),CSS3 3D变换(transforms),WebGL和视频(video)。
      /*
      * 根据上面的结论
      * 将 2d transform 换成 3d
      * 就可以强制开启 GPU 加速
      * 提高动画性能
      */
      div {
        transform: translate3d(10px, 10px, 0);
      }
      复制代码

2.白屏优化

1. DNS解析优化

针对DNS Lookup环节,我们可以针对性的进行DNS解析优化。

  • DNS缓存优化
    • 减少DNS查询次数。 减少DNS查询次数需要减少来自不同domain的请求的数量,如尽量将外部域的对象下载到本地服务器上等。
  • DNS预加载策略
    • 可以通过用meta信息来告知浏览器, 我这页面要做DNS预解析
     <meta http-equiv="x-dns-prefetch-control" content="on" />
    复制代码
    • 可以使用link标签来强制对DNS做预解析:
     <link rel="dns-prefetch" href="http://ke.qq.com/" />
    复制代码
  • 稳定可靠的DNS服务器

2. TCP网络链路优化

针对网络链路的优化,好像除了花钱没有什么更好的方式!

3. 服务端处理优化

服务端的处理优化,是一个非常庞大的话题,会涉及到如Redis缓存、数据库存储优化或是系统内的各种中间件以及Gzip压缩等…

4. 浏览器下载、解析、渲染页面优化

根据浏览器对页面的下载、解析、渲染过程,可以考虑一下的优化处理:

  • 尽可能的精简HTML的代码和结构
  • 尽可能的优化CSS文件和结构
  • 一定要合理的放置JS代码,尽量不要使用内联的JS代码

3.大量图片加载优化

1. 浏览器有连接请求限制,一般浏览器都是最大http连接数被限制在6个,有以下解决方法

    1. 懒加载,没有浏览到的图片暂不请求
      • 判断图片是否是首屏内图片,首先想到的肯定是通过 getBoundingClientRect 方法,获取到图片的位置信息,判断其是否在 viewport 内部。
      const inViewport = (el) => {
          const rect = el.getBoundingClientRect()
      
          return rect.top > 0
            && rect.bottom < window.innerHeight
            && rect.left > 0
            && rect.right < window.innerWidth
        }
      复制代码
    1. 小图片比较多,可以用雪碧图、字体图标、base64等,这样可以有效减少连接数
    1. 在 HTTP/1.0 和 HTTP/1.1 协议下,由于 Chrome 只支持同域同时发送 6 个并发请求,可以进行域名切分,来提升并发的请求数量.
    1. 连接数限制问题还可以由http2来解决,http2一个站点只有一个连接。每个请求为一个流,每个请求被分为多个二进制帧,不同流中的帧可以交错的发送,实现多路复用。这就解决了连接数限制的问题

2、图片过大,传输和渲染比较慢,有以下的处理办法

    1. 如果是相册之类的可以预加载,在展示当前图片的时候,就加载它的前一个和后一个图片
    1. 加载的时候可以先加载一个压缩率非常高的缩略图,以提高用户体验
    1. 使用渐进式jpeg,会提高用户体验
    1. 如果展示区域小于图片的真实大小,可以在服务端先压缩到合适的尺寸

4. 浏览器从输入网址到页面展现的整个过程

  • 1,用户输入url并回车
  • 2,浏览器进程检查url,组装协议,构成完整的url
  • 3,浏览器进程通过进程间通信(IPC)把url请求发送给网络进程
  • 4,网络进程接收到url请求后检查本地缓存是否缓存了该请求资源,如果有则将该资源返回给浏览器进程
  • 5,如果没有,网络进程向web服务器发起http请求(网络请求),请求流程如下:
    • 5.1 进行DNS解析,获取服务器ip地址,端口(端口是通过dns解析获取的吗?这里有个疑问)
    • 5.2 利用ip地址和服务器建立tcp连接
    • 5.3 构建请求头信息
    • 5.4 发送请求头信息
    • 5.5 服务器响应后,网络进程接收响应头和响应信息,并解析响应内容
  • 6,网络进程解析响应流程;
    • 6.1 检查状态码,如果是301/302,则需要重定向,从Location自动中读取地址,重新进行第4步,如果是200,则继续处理请求。

    • 6.2 200响应处理:

      检查响应类型Content-Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行

      后续的渲染,如果是html则通知浏览器进程准备渲染进程准备进行渲染。

  • 7,准备渲染进程
    • 7.1 浏览器进程检查当前url是否和之前打开的渲染进程根域名是否相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程
    1. 传输数据、更新状态
    • 8.1 渲染进程准备好后,浏览器向渲染进程发起“提交文档”的消息,渲染进程接收到消息和网络进程建立传输数据的“管道”
    • 8.2 渲染进程接收完数据后,向浏览器发送“确认提交”
    • 8.3 浏览器进程接收到确认消息后更新浏览器界面状态:安全、地址栏url、前进后退的历史状态、更新web页面。
    1. 渲染流水线
    • 构建 DOM 树
        1. 输入:HTML 文档;
        1. 处理:HTML 解析器解析;
        1. 输出:DOM 数据解构。
    • 样式计算
        1. 输入:CSS 文本;
        1. 处理:属性值标准化,每个节点具体样式(继承、层叠);
        1. 输出:styleSheets(CSSOM)。
    • 布局(DOM 树中元素的计划位置)
        1. DOM & CSSOM 合并成渲染树;
        1. 布局树(DOM 树中的可见元素);
        1. 布局计算。
    • 分层
        1. 特定节点生成专用图层,生成一棵图层树(层叠上下文、Clip,类似 PhotoShop 里的图层);
        1. 拥有层叠上下文属性(明确定位属性、透明属性、CSS 滤镜、z-index 等)的元素会创建单独图层;
        1. 没有图层的 DOM 节点属于父节点图层;
        1. 需要剪裁的地方也会创建图层。
    • 绘制指令
        1. 输入:图层树;
        1. 渲染引擎对图层树中每个图层进行绘制;
        1. 拆分成绘制指令,生成绘制列表,提交到合成线程;
        1. 输出:绘制列表。
    • 分块
        1. 合成线程会将较大、较长的图层(一屏显示不完,大部分不在视口内)划分为图块(tile, 256256, 512512)。
    • 光栅化(栅格化)
        1. 在光栅化线程池中,将视口附近的图块优先生成位图(栅格化执行该操作);
        1. 快速栅格化:GPU 加速,生成位图(GPU 进程)。
    • 合成绘制
        1. 绘制图块命令——DrawQuad,提交给浏览器进程;
        1. 浏览器进程的 viz 组件,根据DrawQuad命令,绘制在屏幕上。
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享