前端性能优化策略

ssddgkke 2019-07-01

注意: 最好是在修改之后进行前后对比,在使用了优化方法之后和没使用的时候,因为就算使用了优化方式,也不一定会起到性能优化的效果,需要据场景而定。

http 请求过程当中潜在的性能优化点

  • 静态资源一般放到 cdn 加快静态资源的获得,但是当我们 cdn 的域名和页面的域名相同的时候,请求会带上不许不需要的 cookies ,所以两者的域名不能一样。
  • dns 缓存, 降低访问 dns 的时间。
  • 对于接口,我们可以减少 http 请求的次数和大小。
  • 浏览器缓存。
  • 页面渲染过程优化。
  • 使用服务端渲染。

资源压缩与合并

在真实的开发中都是使用构建工具(webpack、gulp等)来完成下面的事情

html 压缩

去掉空格、注释、回车、换行。

  • 使用在线网网站进行压缩(实际公司中不适用)。
  • 使用 nodejs 提供的 html-minifier
  • 后端模板引擎渲染压缩。

css 压缩

去掉空格、注释、回车、换行无效代码删除语义合并。

  • 使用在线网网站进行压缩(实际公司中不适用)。
  • 使用 nodejs 提供的 html-minifier
  • 使用clean-cscss进行压缩。

js压缩与混乱

无效字符的删除、剔除注释、代码语义的缩减和优化(如变量名缩短)、代码保护(将js代码混乱,使其不可读)。

  • 使用在线网站进行压缩。
  • 使用html-minifier
  • 使用uglifyjs2js进行压缩 。

文件合并

文件合并可以减少网络请求, 而且浏览器能够同时并发的请求数量有限,当请求过多的时候可能需要等待,文件合并可以减少请求次数,减少等待。但是存在首屏渲染问题(第一次请求时间长)、缓存失效(单个文件的缓存失效会导致合并当中其他文件的缓存失效)的问题。所以有如下的合并建议。

  • 公共库合并: 公共库一般不会变,我们可以将它们进行合并。
  • 不同页面的合并: 针对单页应用,只有当我们跳转到那个页面的时候,才去请求这个页面的资源,将这个页面涉及的资源进行合并。

那么怎么进行文件合并呢?如下:

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

图片优化

每种图片格式都有自己的特点,针对不同的业务场景选择不同的图片格式很重要

  • jgp有损压缩
  • png: 颜色类型丰富的图片,应该选择位数高的png

    • png8: 256色,支持透明
    • png24: 2^24色 不支持透明
    • png32: 2^24色 支持透明

不同格式图片常用的业务场景

  • jpg有损压缩,压缩率高,不支持透明: 大部分不需要透明图片的业务场景
  • png支持透明,浏览器兼容好: 大部分需要透明图片的业务场景
  • webp压缩程度更好,在ios webview有兼容性问题: 安卓全部
  • svg矢量图,代码内嵌,相对较小,图片样式相对简单的场景: 图片样式相对简单的业务场景

图片压缩

  • 可使用tinypng这个网站来压缩

css 雪碧图

把网站上用到的一些图片整合到一张单独的图片当中,从而减少大量的 http 请求的数量。缺点是图片会变大

  • 第一步是将图片合并到一张图片上
  • 第二步是使用在线网站,上传图片,选中指定的图片,然后会有相应的css

Image inline

将图片内嵌到html当中, 减少网站的 http 请求数量, 如使用 base6 的方式插入图片, 一般网站当中一些小的图标可以用它,实际根具情况而定

使用矢量图

使用 svg 进行矢量图的绘制,图片的质量和速度都特别好,使用得也比较多。

寄予页面渲染过程的优化

并发

浏览器对于一个域名的并发请求数量是有限的,所以我们需要设置多个域名,比如 cdn 设置多个域名

懒加载和预加载

懒加载

  • 一般都是对于图片来说,当图片进入可视区域的时候再加载图片
  • url 地址放置到 img 标签当中,当进入可视区的时候,将其取出来设置

预加载

  • 图片等静态资源在使用之前的提前请求
  • 资源使用到的时候从缓存当中加载

有三种方式:

  • 直接在页面上把 img 标签放到前面, 然后 display: none;
  • var image = new Image(); image.src = xxxx; 使其下载下来,后面使用的时候后会直接去缓存拿
  • 使用XMLHttpRequset, urlimage.srcurl, 可以使用它更加精细的对预加载的过程进行控制
  • 使用preload.js

客户端存储

Cookie

用来维护用户状态

  • Cookie的生成方式: 服务端的response.header使用set-cookie, 或者使用document.cookie进行读写
  • 浏览器端在相应的域名下保存

cdn的静态资源不需要Cookie, 但是在相同域名下面,http请求会自动带上Cookie, 解决办法是cdn的域名和主站的域名要不相同。

localstorage

对于不会经常变得数据,可以存在里面

  • html5当中设计出来专门用于浏览器存储的
  • 大小为5M左右
  • 浏览器缓存方案

sessionStorage

  • 会话级别的浏览器存储(一个tab)
  • 大小为5M左右
  • 如使用它进行表单信息的维护(提升用户体验)

IndexedDB

  • 用于客户端存储大量结构化数据
  • 为应用创建离线版本

Service Workers

可以启动一个其他的线程来进行运算, 防止阻塞。

  • 使用拦截和处理网络请求的能力去实现离线应用
  • 使用那个Service worker在后台运行同时能和页面通信的能力。
  • 存储对应于浏览器当中的cache

PWA

是一个 web app 新模型

浏览器自动缓存

需要response-headerrequest-header进行配合,每个文件在进行缓存存储的时候,都会将response-header一起存,方便下一次判断缓存情况时使用response-header当中和缓存相关的头字段。而且如果是直接从缓存当中读取。

命中max-age、expire缓存策略的状态码为200, 命中etag、last-modified、s-maxage缓存策略的时候状态码为304
响应头当中的和缓存相关的头字段以及状态码,都需要我们在服务端判断是否为响应的情况后,手动设置

Cache-Control

可存在于requset-headerresponse-header

  • max-age : 再这个时间之内,再次请求相同资源的时候,浏览器会直接从缓存中取,不会发起请求,状态码为200
  • s-maxage: 优先级高于max-age, 用来设置public的缓存。状态码为 304, 注意这里是去公共的缓存区域取数据,如 cdn, 不是在浏览器本地区数据。
  • private: 在浏览器上的缓存。对应max-age
  • public: 如cnd, 大家都可以访问。对应s-maxage
  • no-cache: 设置了这个属性,不会像max-age一样,如果没有过期,那么直接去缓存取数据,而是会先发起一次请求,这个时候会带上 If-None-Match 或者 if-Modified-since 去服务端询问缓存是否过期,如果没有过期服务端返回304, 然后去缓存区取数据,否者返回200, 并返回新的内容。
  • no-store: 当设置了这个属性,就不会使用缓存策略

Expires

缓存过期时间,比max-age的优先级低

Last-Modified/If-Modified-Since

前面两个头部,可以解决在指定的时间内在缓存当中去取数据,但是当我们的服务端将数据更改之后,客户端并不知道。

服务端返回一个文件最后修改时间Last-Modified, 在请求的时候带上if-Modified-since,在服务端进行比对,如果客户端传过来的时间小于服务器上文件的最后修改时间,那么就返回200,并将相应的最新内容和Last-Modified给返回。否者返回304,文件内容未被修改。

需要注意的是,当设置了max-age的时候,仍然走缓存,只有当max-age过期了之后,这两个字段才会起作用

Etag / If-None-Match

前面的 Last-Modified/If-Modified-Since,存在一个缺点,那就是当服务端Last-Modified修改之后,可能文件内容并没有发生改变,这个时候,其实并没有必要去重新返回内容。所以我们可以使用文件的hash值,只有文件的hash值发生改变之后,文件内容才发生改变。

同样需要注意的是,只有在max-age或者Expire失效之后,Etag / If-None-Match才有效。到服务端进行比对,未改变返回304,改变了返回200

Etag / If-None-Match的优先级比Last-Modified / If-Modified-Since优先级高。

服务端性能优化

用服务端的运算能力,来减轻浏览器端的运算压力。

我们以React为例来说: 当我们访问以为用React写的网站时,首先会下载我们的代码,但是由于React是基于数据驱动的,所以它还要进行一步渲染的过程,会将我们的JSX转换成virtualdom, 然后再转换成html代码,这一过程是需要时间的。

解决方案在服务端将React代码渲染成html之后再返回浏览器端

  • 构建层模板编译
  • 数据无关的prerender方式
  • 服务端渲染

相关推荐