Skip to content

性能优化

分析工具

lighthouse

performance

webpack-bundle-analyzer

webpack中分析打包文件的插件

img.png

webpack-bundle-analyzer

性能优化的目的

  • 1、对用户而言:页面加载得更快,响应更及时,体验更友好,减少用户流失

  • 2、对公司而言:减少资源请求数,减少带宽,节省成本

优化途径有很多,大致可从以下两个角度出发:

a、页面级优化

b、代码级优化

页面级优化

可以用两个角度出发

  • 1、提高请求速度

  • 2、减少请求次数和体积

1、DNS预解析

当浏览器从(第三方)服务器请求资源时,必须先将该跨域域名解析为 IP 地址,然后浏览器才能发出请求。 此过程称为 DNS 解析。 DNS 缓存可以帮助减少此延迟,而 DNS 解析可以导致请求增加明显的延迟,此延迟可能会大大降低加载性能。

会经过:浏览器dns缓存 > 本地host > dns服务器

添加以下link,告诉浏览器先做一个dns的预查询,用到的时候可以直接拿到对于ip

dns-prefetch 可帮助开发人员掩盖 DNS 解析延迟。 HTML 元素 通过 dns-prefetch 的 rel 属性值提供此功能。然后在 href 属性中指要跨域的域名:

使用

html
<html>
<head>
    <link rel="dns-prefetch" href="https://cdn.forguo.cn">
    <!-- and all other head elements -->
</head>
<body>
<!-- your page content -->
</body>
</html>

dns-prefetch

2、预加载

告诉浏览器在合理的时机去提前加载资源

a、preload

使用linkpreload属性预加载一个资源。

html
<link rel="preload" href="style.css" as="style">

as属性可以指定预加载的类型,除了style还支持很多类型,常用的一般是stylescriptcssjs

b、prefetch

prefetchpreload差不多,prefetch是一个低优先级的获取,通常用在这个资源可能会在用户接下来访问的页面中出现的时候。

当然对当前页面的要用preload,不要用prefetch,可以用到的一个场景是在用户鼠标移入a标签时进行一个prefetch。

c、preconnect

preconnectdns-prefetch做的事情类似,提前进行TCP,SSL握手,省去这一部分时间,基于HTTP1.1(keep-alive)和HTTP2(多路复用)的特性,都会在同一个TCP链接内完成接下来的传输任务。

d、script加标记

当浏览器解析至script标签时,浏览器的主线程就会等待script,或者运行script,然后继续开始构建

我们可以给script标签增加标记,使其异步(延迟)运行。

async标记
html
<script src="main.js" async>

async标记告诉浏览器在等待js下载期间可以去干其他事,当js下载完成后会立即(尽快)执行,多条js可以并行下载。

async的好处是让多条js不会互相等待,下载期间浏览器会去干其他事(继续解析HTML等),异步下载,异步执行

defer标记
html
<script src="main.js" defer></script>

与async一样,defer标记告诉浏览器在等待js下载期间可以去干其他事,多条js可以并行下载, 不过当js下载完成之后不会立即执行,而是会等待解析完整个HTML之后在开始执行,而且多条defer标记的js会按照顺序执行

html
<script src="main.js" defer></script>
<script src="main2.js" defer></script>'

即使main2.js先于main.js下载完成也会等待main.js执行完后再执行。

3、使用HTTP2

HTTP/1.1与HTTP/2的区别

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

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

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

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

HTTP/2的多路复用和HTTP/1.X中的长连接复用的区别

  • 1、HTTP/1.X 一次请求-响应,建立一个连接,用完关闭;每一个请求都要建立一个连接;

  • 2、HTTP/1.1 Pipeling解决方式为,若干个请求排队串行化单线程处理,后面的请求等待前面请求的返回才能获得执行机会,一旦有某请求超时等,后续请求只能被阻塞,毫无办法,也就是人们常说的线头阻塞;

  • 3、HTTP/2多个请求可同时在一个连接上并行执行。某个请求任务耗时严重,不会影响到其它连接的正常执行;

nginx开启http2

nginx
server {
    listen 443 ssl http2; # 加一句 http2.
    server_name domain.com;
}

http2

4、使用缓存

强缓存

js和css添加强缓存

内容不变时,直接从缓存中读取 内容变化时,从服务器获取新的资源

状态码均为200

协商缓存

html添加协商缓存

向服务器发送请求,服务器判断内容是否变化,返回304,浏览器从缓存中读取 内容变化,返回200,并返回新的资源

浏览器缓存

5、使用CDN

CDN会把源站的资源缓存到CDN服务器,当用户访问的时候就会从最近的CDN服务器拿取资源而不是从源站拿取,这样做的好处是分散了压力,同时也会提升返回访问速度和稳定性。

6、资源压缩与合并

对资源进行合理的压缩以及合并,减少请求次数和大小

  • 1、html、css、js、image等压缩

  • 2、雪碧图

  • 3、字体图标(iconfont)

  • 4、合并js、css等资源

  • 5、开启GZIP,压缩资源

webpack优化

代码级优化

1、合理使用闭包

2、事件委托

3、减少DOM操作

多次dom操作可使用createFragment,创建虚拟dom切片

4、长列表优化

将不在视图范围内的dom使用占位元素代替

5、懒加载

路由懒加载、组件懒加载、图片懒加载

import()代替import

6、减少重绘和回流

  • 重绘

改变元素的color,background等外观样式,导致重绘

  • 回流

改变元素的大小,位置等样式,导致回流

  • 优化

合并样式修改

批量操作DOM

回流一定重绘,重绘不一定回流

7、节流和防抖

节流 throttle

稀释函数的执行频率

javascript
function throttle(fn, delay) {
    let lastTime = 0
    return function () {
        let now = Date.now()
        if (now - lastTime > delay) {
            fn.apply(this, arguments)
            lastTime = now
        }
    }
}

防抖 debounce

固定时间不可再次触发

javascript
function debounce(fn, delay) {
    let timeout = null
    return function () {
        timeout && clearTimeout(timeout)
        timeout = setTimeout(() => {
            fn.apply(this, arguments)
        }, delay)
    }
}