前端性能上的建议

x33g5p2x  于2022-03-31 转载在 其他  
字(4.9k)|赞(0)|评价(0)|浏览(260)

一、写在前面

昨天字节二面,感觉要挂了,其中问了一个问题就是关于前端性能上的问题,我就简单讲了gzip压缩,异步组件的分包,还有就是图片的懒加载,哈哈哈,然后就不会了,紧接着面试官一直在问,还有吗,还有吗,我:不知道了。

二、具体总结

1、减少http请求

一个完整的http请求需要经历DNS查找,TCP握手,浏览器发出HTTP请求,服务器接受请求,服务器处理请求并发出相应,浏览器接受相应等过程。接下来看一个具体的例子帮助我们理解http

如上所示,这是一个http请求的具体时间。
名词解释:

Queueing: 在请求队列中的时间。
Stalled:从TCP连接建立开始,到真正可以传输数据之间的时间差,此时键包括代理协商的时间。
Proxy negotiation: 与代理服务器建立进行协商花费的时间。
DNS lookup:执行DNS查找所花费的时间,页面上的每一个不同的域都需要进行DNS查找。
Initial Connection / Connecting: 建立连接所花费的时间,包括TCP握手/重试和协商SSL。
SSL: 完成SSL握手所花费的时间。
Request sent: 发出网络请求所花费的时间,通常为一毫秒的时间。
Waiting(TFFB): TFFB 是发出页面请求到接收到应答数据第一个字节的时间。
Content Download: 接收响应数据所花费的时间。

从这个例子我们可以看出,真正下载的数据的时间占比为13.05 / 204.16 = 6.39%,文件越小,这个比例越小,文件越大,这个比例就越高。这就是为什么要建议将多个小文件合并为一个大文件,从而减少http请求的次数的原因。

2、使用HTTP2

HTTP2相比于HTTP1.1存在如下几个优点。
多路复用
HTTP1.1如果要同时发起多个请求,就得建立多个TCP连接,因为一个TCP连接同时只能处理一个HTTP1.1的请求。
HTTP2上,多个请求可以共同一个TCP连接,这称为多路复用。多个请求和响应在TCP连接中可以乱序发送,到达目的地再通过流ID重新组建。
首部压缩
HTTP2提供了首部压缩的功能。
例如如下所示的两个请求

:authority: unpkg.zhimg.com
:method: GET
:path: /za-js-sdk@2.16.0/dist/zap.js
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
pragma: no-cache
referer: https://www.zhihu.com/
sec-fetch-dest: script
sec-fetch-mode: no-cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36
:authority: zz.bdstatic.com
:method: GET
:path: /linksubmit/push.js
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: zh-CN,zh;q=0.9
cache-control: no-cache
pragma: no-cache
referer: https://www.zhihu.com/
sec-fetch-dest: script
sec-fetch-mode: no-cors
sec-fetch-site: cross-site
user-agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.122 Safari/537.36

从上面的两个请求可以看出,很多数据都是重复的。如果可以把相同的首部存储起来,仅发送他们之间不同的部分,就可以节省很多的流量,加快请求时间。
下面看一个简化的例子:假设客户端按顺序发送如下请求:

Header1:foo
Header2:bar
Header3:bat

当客户端发送请求时,他会根据首部值创建一张表。

索引 首部名称
62Header1
63Header2
64Header3

如果服务器收到了请求,它会创建一张表。当客户端发送下一个请求的时候,如果首部相同,它可以直接发送这样的首部块。

62 63 64

优先级
HTTP2可以对比较紧急的请求设置比较高的优先级,服务器在收到这样的请求后,可以优先处理。
服务器推送
HTTP2新增一个强大的功能,就是服务器可以对一个客户端请求发送多个响应。换句话说,处理对最初请求的响应外,服务器还可以额外向客户端推送资源,而无需客户端明确地请求。
例如:当浏览器请求一个网站时,除了返回HTML页面外,服务器还可以根据HTML页面中的资源的URL,来提前推送资源。

3、服务端渲染

我们可以采用服务端渲染来代替客户端渲染
什么是服务端渲染:就是页面中的数据都填充完毕,并且在后端进行相应的计算,最后将完整的html页面返回给前端渲染。
什么是客户端渲染:首先渲染的网站请求html页面,然后进行解析,在前端生成DOM树并进行渲染以及数据填充。
这样做的好处: 假如一个网站需要加载四个资源,假设每一个资源文件大小都为1M。此时客户渲染需要加载的文件都五个,才可以完成首页渲染。而服务端渲染只需要加载一个html页面即可,大概也就是几百KB左右,所以服务端渲染的速度就会更快,如果采用服务端渲染方式,则不仅首屏加载快,而且SEO好,但是也存在一些缺点:比如说增加服务器的计算压力。

4、CDN原理

当用户访问一个网站时,如果没有CDN,过程是这样的。

1、浏览器要将域名解析为IP地址,所以需要向本地DNS发出请求。
2、本地DNS依次向根域名服务器,顶级域名服务器,权威域名服务器发出请求,得到网站服务器的IP地址。
3、本地DNS将IP地址发回浏览器,浏览器向网站服务器IP地址发出去请求并得到资源。

如果用户访问的网站部署了CDN,过程是这样的。

1、浏览器要将域名解析为IP地址,所以向本地DNS发出请求。
2、本地DNS依次向根域名服务器,顶级域名服务器,权威域名服务器发出请求,得到全局负载均衡系统(GSLB)的IP地址。
3、本地DNS服务器再向GSLB发出请求,GSLB的主要功能是根据本地DNS的ip地址判断用户的位置,筛选出距离用户较近的本地负载均衡系统(SLB),并将(SLB)的ip地址作为结果返回给本地DNS。
4、本地的DNS将SLB的ip地址发送给浏览器,浏览器向SLB发出请求。
5、SLB根据浏览器请求的资源和地址,选出最优的缓存服务器发送给浏览器。
6、浏览器再根据SLB发出的地址重定向到缓存服务器。
7、如果缓存服务器有浏览器需要的资源,就将资源发送给浏览器,如果没有,则就想源服务器发送请求并且请求资源,再发给浏览器并缓存到本地。

5、将CSS放到文件头部,JavaScript文件放到文件底部

css执行会阻塞渲染,js执行会阻塞html解析,阻止cssom构建。
如果css, js标签放到head标签中,并且需要加载和解析很久的话,那么页面就空白了。所以js文件要放到底部,等html解析完了再加载js文件,尽快的让用户看到页面。
那么为什么css文件还要放到头部呢?
因为先加载html再加载css,会让用户第一时间看到的页面是没有样式的,为了避免这种情况的发生,就要将css文件放到头部了。
此外,js文件也不是不可以放到头部,只要给script标签加上defer属性就可以了,异步下载,延时执行。
6、使用字体图标iconfont代替图片图标
字体图标就是将图标制作为一个字体,使用时就跟字体一样,可以设置属性,例如:font-size,color等,非常方便。并且也可以使用fontmin-webpack对字体文件进行压缩。

7、善用缓存
可以使用强缓存和协商缓存来避免前端向后端重复请求。
8、压缩文件
压缩文件可以减少文件下载的时间,让用户体验性更好。得益于webpacknode的发展,现在的压缩文件已经非常方便了。在webpack可以使用如下插件进行压缩。

javascript: Uglifyplugin
css:MinicssExtractPlugin
html: HtmlWebpackplugin

其实,还可以做得更好。那就是使用gzip压缩。可以通过向 HTTP 请求头中的 Accept-Encoding头添加gzip 标识来开启这一功能。当然,服务器也得支持这一功能。
gzip是目前最流行和最有效的压缩方式。
9、图片的优化
1、图片的延迟加载
在页面中,先不给图片设置路径,只有当图片出现在浏览器的可视区域时,才会去正在的加载图片,这就是延迟加载。对于图片很多的网站来说,一次性加载全部的图片,会对用户体验造成很大的影响,所以需要使用图片延迟加载。
首先可以将图片这样设置,在页面不可见的时候图片就不会加载。

<img data-src="https://avatars0.githubusercontent.com/u/22117876?s=460&u=7bd8f32788df6988833da6bd155c3cfbebc68006&v=4">

等页面可见时,使用js加载图片。

const img = document.querySelector('img')
img.src = img.dataset.src

这样图片就加载出来了。
2、响应式图片
响应式图片的优点是浏览器能够根据屏幕大小自动加载合适的图片。
通过picture实现

<picture>
	<source srcset="banner_w1000.jpg" media="(min-width: 801px)">
	<source srcset="banner_w800.jpg" media="(max-width: 800px)">
	<img src="banner_w800.jpg" alt="">
</picture>

通过@media实现

@media (min-width: 769px) {
	.bg {
		background-image: url(bg1080.jpg);
	}
}
@media (max-width: 768px) {
	.bg {
		background-image: url(bg768.jpg);
	}
}

3、调整图片大小
例如:如果你有1920 × 1080大小的图片,用缩略图的方式展示给用户,并且当用户鼠标悬停在上面时才展示全图。如果用户从未真正将鼠标悬停在缩略图中,则浪费了下载图片的时间。所以我们可以先加载缩略图,当用户悬停上面时,再更改图片的src进行下载。
4、降低图片质量
例如JPG格式的图片,100%的质量和90%质量的通常看不出来,尤其是用在当背景图的时候。所以我们可以采用减低图片质量的方式来减少带宽。常用到的压缩图片的方式有:一、webpack插件压缩——image-webpack-loader二、通过在线网站进行压缩。
5、尽可能的使用css3效果来代替图片
很多图片的效果都是可以使用css画出来的,这种情况选择css3效果更好,因为代码通常是图片大小的几分之一甚至几十分之一。
6.、使用webp的图片
WebP 的优势体现在它具有更优的图像数据压缩算法,能带来更小的图片体积,而且拥有肉眼识别无差异的图像质量;同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,在 JPEG 和 PNG 上的转化效果都相当优秀、稳定和统一。

相关文章