Web前端性能优化

资源合并与压缩

Html压缩

HTML代码压缩就是压缩这些在文本文件中有意义,但是在HTML中不显示的字符,包括空格、制表符、换行符等,还有一些其他意义的字符,如HTML注释也可以被压缩。

压缩方式:

  • 使用在线网站进行压缩

  • nodejs提供的html-minifier工具

  • 后端模板引擎渲染压缩

Css、JS压缩与混乱

css:无效代码的删除、css语义合并,JS:无效字符的删除、剔除注释、代码语义的缩减和优化、代码保护。

压缩方式:

  • 使用在线网站压缩

  • 使用html-minifier对html中的Css进行压缩、对Html中JS进行压缩

  • 使用clean-css对css进行压缩

  • 使用uglifyjs2进行JS压缩

文件合并压缩

假设a.js、b.js、c.js三个文件,不合并压缩将会导致多次请求,文件与文件之间将会导致多个请求,增加网络延迟,丢包问题严重,keep-alive经过代理服务器获取资源也存在连接断开的问题。

文件合并存在的问题(合并结果abc.js),当渲染依赖于js文件时,将必须等到js文件加载,当合并文件abc.js太大,将会导致首屏渲染问题(空白页),例如Vue、React框架等,如果未使用服务端渲染时,必须要等框架代码加载完成,才能进行加载渲染,也会导致缓存失效问题,Js文件都是具有缓存性的,当任意一个文件被修改,都会导致全局abc.js文件改动。

改善:公共库合并(公共库与业务代码分割)、不同页面合并(对于单页面应用的某个页面被路由到才去发起请求,加载对应的页面组件)。

压缩方式:

  • 使用在线网站进行文件合并
  • 使用nodejs实现文件合并

图片优化

图片压缩

使用在线压缩工具压缩图片,减小图片体积,针对不同浏览器采用不同类型图片。

图片雪碧图

多张图片合并(雪碧图),通过css截取选取图片位置,注意:可以设计多张雪碧图,针对不同加载采用设计,防止全局图片依赖加载过程太长。

CSS和JS加载过程

输入浏览器地址,从服务器获取Html、JS、CSS数据,在页面构造中,解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本(并行)。解析过程中遇到图片、样式表、js文件,启动下载。

构建DOM树:

  • Tokenizing:根据HTML规范将字符流解析为标记

  • Lexing:词法分析将标记转换为对象并定义属性和规则

  • DOM construction:根据HTML标记关系将对象组成DOM树

构建CSSOM树

  • Tokenizing:字符流转换为标记流

  • Node:根据标记创建节点

  • CSSOM:节点创建CSSOM树

构建RenderTree渲染树:

  1. 从DOM树的根节点遍历所有可见节点,不可见节点包括:script,meta这样本身不可见的标签、被css隐藏的节点,如display: none
  2. 对每一个可见节点,找到恰当的CSSOM规则并应用
  3. 发布可视节点的内容和计算样式

JS解析过程:

  • 浏览器创建document对象解析HTML,将解析到的元素和文本节点添加到文档中,此时document.readystate为loading。
  • 解析到无async和defer的script脚本,将他们添加到文档中,执行行内或者行外的脚本,同步执行,在脚本下载和解析过程中解析器会暂停,以document.write()写入页面。
  • 当遇到async的脚本,会开始下载脚本,下载中页面仍然继续解析,脚本下载完成后会立即执行
  • 文档解析完成后,document.readstate状态转变为interactive。
  • 所有defer脚本,将会按照在文档中出现的次序依次顺序执行
  • 注意:异步脚本执行,其中禁止使用document.write(),会导致页面结构改变。
  • 浏览器在Document对象上触发DOMContentLoaded事件
  • 文档完全解析完成,但是可能存在类似图片加载未完成,等待这些内容加载完成并且所有异步脚本完成载入和执行,docume.readstate变为complete,window触发load事件
  • 逐步的显示页面。

HTML渲染过程的特点:

  • 顺寻执行、并发加载。(浏览器并发存在上限)

  • 是否阻塞。(css加载是否会阻塞页面渲染和JS执行等)

  • 依赖关系。(css在head中才会显示最终渲染好附带样式的页面、否则可能从在无样式页面,async脚本执行无序)

  • 引入方式。(css使用link还是@import方式,link会阻塞页面加载,@import实在页面解析完成后执行,JS引入方式async、defer、module )

懒加载和预加载

懒加载:对未进入可是区域中的图片,将真实地址放置在data-url中,当进入视野,替换src属性。

  • 图片进入可视区域后请求图片资源
  • 对于电商等图片很多,页面很长的业务场景适用
  • 减少无效资源的加载
  • 并发加载的资源过多会阻塞JS的加载,影响网站的使用

预加载:对于接下来将显示的内容进行预加载(例如:轮播时将下次显示的图片也加载出)。

  • 图片等静态资源在使用之前的提前请求
  • 资源使用到时能从缓存中加载,提审用户体验
  • 页面展示的依赖关系维护

重绘与重流

重绘:当RenderTree中一些元素需要更新属性时,但是这些属性仅仅是影响元素的外观、风格,而不会影响布局的,比如background-color,则称为重绘。

回流:当RenderTree中一部分(或全部)因为元素的规模尺寸、布局、隐藏等改变而需要重新构建。这就成为回流。每个页面初次加载即发生回流。在回流中,因为渲染树中受影响的部分失效,并且重新构造这部分渲染树,完成回流后,则需要将绘制受影响内容重新替换到页面,则称为重绘。

区别:

  • 回流将导致重绘,重绘不一定导致回流。
  • 当页面布局和几何属性改变触发回流。

触发回流的页面布局条件:

盒子模型相关属性、定位属性以及浮动、改变节点内容,具体属性:

CSS属性:width height padding margin display border-width border min-height top left right bottom position float clear line-height text-align overflow-y font-weight overflow font-family vertival-align white-space font-size。

触发重绘的条件:

CSS属性:color、border-style、border-radius、visibility、text-decoration、background、background-image、background-position、background-repeat、background-size、outline-color、outline、outline-style、outline-width、box-shadow。

避免重绘、回流方法:

避免使用触发重绘、回流的CSS属性或者将重绘、回流的影响范围限制在单独的图层内,原因如下:

新建DOM过程:

  • DOM将会被分割为多个图层
  • 对每个图层的节点样式进行计算(Recalculate style--样式重新计算)。
  • 为每个节点生成图形和位置(Layout--回流和重布局)。
  • 将每个节点绘制填充到图层位图中(Paint SetUp 和 Paint--重绘)。
  • 图层做为纹理上传至GPU。
  • 符合多个图层到页面上生成最终屏幕图像(Composite Layers -- 图层重组)。

因此,将频繁重绘回流的DOM元素单独做为一个独立图层,该DOM元素的重绘和回流的影响只会影响这个图层,但是当图层太多,将会导致图层合并Composite Layers时间太长。除此之外,Chrome也存在创建图层条件:3D或透视变换CSS(transform 、perspective)、视频编码(video)、3D上下文或者加速的2D上下文的节点(WebGL 和 Canvas)、混合插件(Flash)、对opacity元素做动画或者使用一个动画webkit变换的元素、拥有加速CSS过滤器的元素、元素拥有子元素(子元素有属于自己的图层)、元素拥有z-Index属性且包含符合层的兄弟元素(图层上下位关系)。

图层查看方式: