6

阅读此文前,请先阅读:性能优化第一步:性能瓶颈分析https://segmentfault.com/a/11...

1.性能优化手段有哪些?

image.png

2.我们利用这些手段具体做了些什么?

网络环境默认为fast 3g disable cache

构建优化

1.采用同构渲染(服务端渲染+客户端渲染)

a.什么是同构渲染,服务端渲染和客户端渲染

服务端渲染(Server Side Render),其实非常好理解,就是服务器返回一堆html字符串,然后让浏览器显示。与服务端渲染相对的是客户端渲染(Client Side Render)。

客户端渲染(Client Side Render):在浏览器中通过JS直接进行页面的渲染路由跳转等操作。比如:创建一个新的React项目,用脚手架生成项目,然后run起来。 这里你可以看到React脚手架自动生成的首页。打开页面源代码
image.png

body中除了兼容处理的noscript标签之外,只有一个id为root的标签。那首页的内容是从哪来的呢?很明显,是下面的script中拉取的JS代码控制的。因此,CSR和SSR最大的区别在于前者的页面渲染是JS负责进行的,而后者是服务器端直接返回HTML让浏览器直接渲染。

同构渲染:前后端共用一套JS代码,采用不同的构建方式。通过Node服务器进行页面的首屏生成。

SSR和CSR的渲染流程图:
image.png

同构渲染的渲染流程图:
image.png

b.他们的优缺点分别是什么?

SSR:

优点:

1.优秀的SEO

2.首屏加载快

缺点:

1.负载大:由于渲染任务都交由服务端进行,在高并发的情况下,对于服务端负载压力大。
2.复用性能差:因为返回的是整个页面,对于每个路由都要重新进行页面刷新,复用性能 上不友好。
3.前后端耦合严重,前端开发依赖于后端,开发形式上不友好。

传统CSR:

优点:
1.节省服务器性能。
2.局部刷新,无需每次都请求完整页面,体验更好。
3.前后端分离开发。

缺点:

1.由于页面显示过程要进行JS文件拉取和React代码执行,首屏加载时间会比较慢。

2.对于SEO(Search Engine Optimazition,即搜索引擎优化),完全无能为力,因为搜索引擎爬虫只认识html结构的内容,而不能识别JS代码内容。

同构渲染:

优点:兼顾前端渲染的大部分优点和后端渲染SEO和首屏加载的优点

缺点:1.需要额外的开发构建成本 2.对服务器有一定负载

c.使用之后效果如何?

CSR的效果

image.png

同构渲染的效果

image.png

通过对比,同构渲染 在下载html文件时,耗费的时间会多出(800ms-580ms)220ms的样子(因为文档内容较多的原因)

CSR的白屏时间为3.8s

同构渲染的白屏时间为0.9s

但是,同构渲染在加载html文件的时间就几乎等于白屏时间,而CSR加载完html文件的时间远小于它的白屏时间。故我们可以看出,同构渲染渲染大大减少了我们页面的白屏时间,同时也减少了首屏时间。

d.具体在项目中的使用

因为我们项目本来是CSR的,如果全部改成SSR,那么成本会很大,而且我们的初衷只是提高性能,并不是一定要用SSR,所以我们就结合了一下,使用了同构渲染。即在服务器端执行一次,用于实现服务器端渲染(首屏直出),在客户端再执行一次,用于接管页面交互,获取需要的对应的数据,核心解决首屏渲染慢的问题。到这里大家一定会有疑问:

Q1:为什么不在服务端通过请求接口的形式,把所有信息都拿到,这样就不用走一遍前端渲染了?

A1:因为我们的项目需要在微信中打开,然后通过微信授权的形式,拿到对应的用户信息,然后再根据用户的信息发出请求以及对页面展示效果作出调整。所以在前期服务端渲染时,拿不到所有的信息,需要通过同构渲染的方式才能完成整个页面的渲染。

Q2:服务端渲染完了,前端再渲染一次,这样会消耗性能或者影响展示效果吗?

A2:不会,前端渲染会去做比较,只会渲染需要改变的DOM,而不会去改变其他的DOM。

2.按需加载

在优化手段的图中,构建优化这一块,除了我们使用同构渲染,其他的中心思想都是在讲,如何做到按需加载,下面我们就这一块具体来讲一讲。

1.首先我们需要确定的就是我们首屏中有哪些资源是必需的,哪些资源是非必需。js都是要做到异步加载的,同时根据情况调整成延迟加载和延迟执行的。

2.其次是给我们首屏中的那些必需的资源,排一个加载顺序,做到尽量不影响我们的页面展示,影响展示的就延迟加载或者延迟执行。

a.js的异步加载,延迟加载,延迟执行

先解释标题,异步加载,延迟执行这2点是可以通过script标签加defer属性来做到,目的是不阻塞渲染,而延迟加载需要视业务场景来调整js文件的位置,目的是减少前期http并发请求数,减少首屏时间。

1.说说什么是defer,async,以及defer和async的区别是什么

defer 和 async 是 script 标签的两个属性。

对于defer,加载后续文档元素的过程将和 此js 的加载并行进行(异步),但是 js 的执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成。不过defer会按照原本的js的顺序执行,所以如果前后有依赖关系的js可以放心使用。(总结一下就是异步加载,延迟执行)

对于async,这个是html5中新增的属性,它的作用是能够异步的加载和执行脚本,不因为加载脚本而阻塞页面的加载,一旦加载到就会立刻执行。在有async的情况下,js一旦下载好了就会执行,所以很有可能不是按照原本的顺序来执行的。如果js前后有依赖性,用async,就很有可能出错。

没有 defer 或 async,浏览器会立即加载并执行指定的脚本,“立即”指的是在渲染该 script 标签之下的文档元素之前,也就是说不等待后续载入的文档元素,读到就加载并执行。

两者的区别:

相同点:a.不会阻塞页面渲染 b.对于inline的script(内联脚本)无效 c.有脚本的onload的事件回调

不同点:a.html的版本html4.0中定义了defer;html5.0中定义了async b.defer 执行要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成,而每一个有async属性的脚本都在它下载结束之后立刻执行,同时会在window的load事件之前执行。所以就有可能出现脚本执行顺序被打乱的情况。

2.具体在这个项目中的使用场景

七鱼客服的SDK 和 微信的SDK,都属于我们刚刚说的,按需加载的第二点,这2个js都属于首屏中需要的文件,但是却需要延迟加载或者异步加载延迟执行的js。

其中七鱼客服的SDK可以延迟加载,延迟执行的,因为一般情况用户一进来页面是不会去立即点击咨询的,所以会给这个script加上defer属性,做到延迟执行,同时,在咨询按钮所在的footer组件中,走到componentDidMount生命周期时才去加载七鱼客服的SDK,就可以做到不阻塞渲染,减少前期http并发请求数,减少首屏时间。

其次,微信的SDK也是属于可以延迟加载,延迟执行的。我们的项目是在微信中打开的,在项目中我们需要先加载了微信的SDK,然后设置了微信分享的相关配置,才能点击分享。因为一般用户进来也不会立即去点击分享,所以会放到微信授权成功之后,再去加载微信的SDK,再通过script 标签上的onload回调函数,去设置微信分享的相关配置,同时给它加上defer属性,这样就做到了延迟加载,并且延迟执行。

对比调整前后的performance图

微信SDK调整前:
image.png

微信SDK调整后:
image.png

可以看到 调整后微信SDK的加载几乎对首屏加载没有较大的影响了。

b.webpack打包策略

默认的分包策略为:

1新的 chunk 是否被共享或者是来自 node_modules 的模块

2.新的 chunk 体积在压缩之前是否大于 30kb

3.按需加载 chunk 的并发请求数量小于等于 5 个

4.页面初始加载时的并发请求数量小于等于 3 个。

推荐阅读 https://juejin.im/entry/5b784... 这里是对webpack分包策略的分析。

总结性地来讲,webpack分包是一个博弈的过程,需要结合具体的业务场景来决定是否分包。但是在我们做性能优化的时候,有些基本点可以注意:

1.一些很小的包 比如只有几kb,但是由图可以看出
image.png

这个包绝大部分时间都花在了建立连接上,而它实际只有1.7kb.这样就可以考虑不拆这个包,将这个包和其他资源合并。

2.一些很大的包(具体怎么衡量包的大小,参考webpack默认的30kb)视它阻塞渲染的程度考虑是否拆包。

3.对打包的文件,要尽量压缩,减少其大小。

对于静态资源的优化

1.图片资源的优化

a.对图片做压缩,在项目中对图片大小的要求是:1.gif不超过1M 2.其余不超过200kb3.宽度最多为页面宽度三倍。
b.兼容性的写法:通过<picture>元素使用在不同情景下使用不同格式的图片,优先级依次为webp,渐进式jpeg, png。

首先是对picture标签的介绍:HTML <picture> 元素通过包含零或多个 <source> 元素和一个 <img> 元素来为不同的显示/设备场景提供图像版本。浏览器会选择最匹配的子 <source> 元素,如果没有匹配的,就选择 <img> 元素的 src 属性中的URL。然后,所选图像呈现在<img>元素占据的空间中。

eg:
image.png

oss 就支持转 webp, 只需要在图片链接后面加上?x-oss-process=image/format,webp 就可以了,不需要自己手动去转,iOS不支持webp,所以会在iOS设备上使用渐进式jpeg,对应的渐进式jpeg图片的说明 (confluence文档地址使用渐进式JPEG来提升用户体验),对于需要使用到透明度的图片才推荐使用png,否则不推荐使用png格式的图片。

c.对非首屏图片(img 背景图 视频的预览图)做懒加载。对于首屏的图片做懒加载反而会增加首屏时间。懒加载的npm包地址 https://gitlab.xiguacity.cn/e...

2.使用CDN

将我们打包的静态资源文件上传到阿里云上。

其他优化手段

1.http/2

http/2这一块,由于不是由前端去设置,但是需要大家对它有所了解。

a.http/2是什么?
HTTP/2(超文本传输协议第2版,最初命名为HTTP 2.0),简称为h2或h2c,是HTTP协议的的第二个主要版本。

b.http/2和http/1.X相比有什么优势?
a.新的二进制格式(Binary Format),HTTP1.x的解析是基于文本。基于文本协议的格式解析存在天然缺陷,文本的表现形式有多样性,要做到健壮性考虑的场景必然很多,二进制则不同,只认0和1的组合。基于这种考虑HTTP2.0的协议解析决定采用二进制格式,实现方便且健壮。

b.多路复用(MultiPlexing),即连接共享,即每一个request都是是用作连接共享机制的。一个request对应一个id,这样一个连接上可以有多个request,每个连接的request可以随机的混杂在一起,接收方可以根据request的 id将request再归属到各自不同的服务端请求里面。

c.header压缩,如上文中所言,对前面提到过HTTP1.x的header带有大量信息,而且每次都要重复发送,HTTP2.0使用encoder来减少需要传输的header大小,通讯双方各自cache一份header fields表,既避免了重复header的传输,又减小了需要传输的大小。

d.服务端推送(server push),同SPDY一样,HTTP2.0也具有server push功能。

2.server workers

a.server wokers是什么?
service worker 是独立于当前页面的一段运行在浏览器后台进程里的脚本。

service worker不需要用户打开 web 页面,也不需要其他交互,异步地运行在一个完全独立的上下文环境,不会对主线程造成阻塞。基于service worker可以实现消息推送,静默更新以及地理围栏等服务。

b.它能解决什么问题?
Service Worker 可以使你的应用先访问本地缓存资源,所以在离线状态时,在没有通过网络接收到更多的数据前,仍可以提供基本的功能监控。

我们在做页面性能优化时,也考虑过使用server workers,一般server works是在第二次访问时能访问到已有的本地缓存资源,我们的项目的用户一般只会访问一次,所以我们项目中没有使用这个方法,只是介绍给大家以后解决问题可以多一种思路。

3.结语

以上就是我们在优化项目中所用到的性能优化手段,其中存在有很多可以改进和调整的地方,也欢迎大家都提出来。在性能优化这一块我们也会持续地去做,在做的同时沉淀下来的文档,也希望对大家以后在对自己项目进行性能优化的时候能有所帮助。


notself
134 声望13 粉丝