Web应用性能优化随笔
优化思路是什么?
BIG QUESTION: 当我们谈到一个web应用的性能优化,应该从哪些方面去考虑?
思路就是,当我们去访问一个web应用的时候,都做了哪些操作?对应这些操作的,就是我们所能进行的优化的模块!
- 浏览器请求DNS服务器,获取IP地址;
- 建立TCP连接;
- 浏览器发出详细请求,通常为HTTP(s)、WebSocket之类;
- 服务器响应请求,并返回数据;
- 浏览器渲染返回的数据到页面;
- 释放TCP连接;
那么,我们接下来就按照这个流程,一步一步来看如何进行优化。
不好控制和不重要的优化内容
1. DNS
首先,DNS查询的流程如下图所示
当有浏览器缓存时,就不会去查询之后的步骤,有无缓存的对比如下图
可以看到,DNS Lookup
这一步,在有缓存之后就不会出现。
2. TCP连接建立
同样如上图所示,Initial Connection
所占用的时间即为TCP建立连接的耗时。由于TCP建立需要3次握手的操作,使其成为HTTP(s)协议通信耗时最长的过程。
针对这个过程,我们可以使用HTTP Keep-Alive
机制,来保持TCP连接状态,这样可以使客户端不需要在每次http请求的时候都去与服务器建立TCP连接,可以节省掉很大的时间开支、提高服务器吞吐率。
之所以说这个也是不好控制和不重要的优化点,是因为现代浏览器已经默认支持 Keep-Alive,而常用的Web服务器也都可以对应进行支持。
如需手动设置,要注意 timeout
和 max
参数,保持时间太长的TCP连接,也会对服务器造成无用资源消耗。
重要的优化内容
3. 浏览器请求和服务器响应
针对请求和响应的优化,简而言之,就是:
- 减少请求次数
- 降低请求耗时
在这里,可做的优化点包括:
- CDN
- 压缩传输,即GZIP/Deflate
- 前端模块化
- 使用缓存
- 使用本地存储
- 负载均衡:Nginx/SLB
3.1 CDN
CDN是Web应用优化的基础,也是最重要最影响用户体验的一个环节!
在项目中,需要注意将打包后的资源文件上传到CDN地址,并且在构建工具中配置相关CDN信息。
3.2 数据压缩
服务端与客户端的数据交互可通过压缩来进行优化,常用的压缩方式是 GZip
和Deflate
,本文以 GZip
为例。GZip
支持 HTML/CSS/JS/XML/PlainText等多种格式的压缩。
下图可看出是否使用压缩,对于传输文件大小的影响。
3.3 前端模块化
前端模块化便于文件管理、也更利于资源归类压缩,模块化大致经历了如下历程。
script -> 闭包函数 -> AMD -> CMD -> CommonJS -> ES6
而对应的构建工具,也有以下发展历程。
Grunt/Gulp -> Browserify -> Webpack
前端模块化详情可参见 《Web前端模块化方法》
3.4 使用缓存
当客户端使用服务端返回的内容时,可以通过缓存机制,减少请求传输次数。
缓存分为 强制缓存
和协商缓存
两种。
强制缓存使用 Expires
和 Cache-Control:max-age
控制缓存有效时间。
协商缓存使用 Last-Modified
配合 ETag
控制缓存有效时间。
通常来讲,系统优先匹配强制缓存。
对于静态资源,系统需要做好相关缓存,避免重复请求。
3.5 使用本地存储
使用本地存储,可以在一定程度上减少服务器请求,也可以加快内容展示速度。
本地存储的使用有以下历程:
Cookie+变量 -> WebStorage -> 单页面内存式存储 -> IndexDB
变量 + Cookie
- Cookie 被设计来管理状态,但在简单应用中可存储数据
- 4KB限制 + 域名绑定
单页面内存式存储
- 针对单页面应用设计的变量存储
- 如VueX
Web Storage
- LocalStorage & SessionStorage
- 区别:生命周期、作用域
IndexDB
- 终极方案、NoSQL
3.6 负载均衡
通常负载均衡包含4中模式:
4. 浏览器渲染
4.1 Async和Defer
对于资源文件的引入,使用 async
和defer
。async
没有固定顺序,即加载到文件就会引入;defer
会按照dom顺序进行插入。
4.2 懒加载
内容的懒加载,如配合 vue-router的按需加载;
图片的懒加载,即需要展示时才去加载。
4.3 图片优化
图片优化是渲染层面能够最大程度提升性能的优化模块,也是操作起来最麻烦、需要投入精力最多的模块。
笔者认为大致分为三个方向:
- 源:确保所有的图片都从CDN源获取
- 裁剪:使用正确大小的图片
- 格式:按需使用格式
源和裁剪都比较明确,格式方面我们细说一下。
常用格式包括:
- JPG:
体积小、有损压缩、不支持透明 - PNG:
体积大、无损压缩、支持透明 - SVG:
文本文件、体积小、不失真、兼容性好 - BASE64:
文本文件、依赖编码、小图标解决方案;
需要少量小图标时可以使用此方案,需要大量小图标时建议使用CssSprites; WebP
新格式,支持动图、体积小;浏览器支持的兼容性差。# 阿里在1688网站上的使用方法可以借鉴: https://alicdn.com/xxx.jpg_xxx.webp
4.4 Throttle & Debounce
节流(Throttle)
在某段时间内,不论触发了多少次回调,都只做第一次,并在结束时给出响应。
防抖(Debounce)
在某段时间内,不论触发了多少次回调,都只做最后一次,并在完成后给出响应。
节流和防抖的目标,都是减少执行,降低损耗,减少卡顿。
示例如下:
Throttle示例
let flag = false window.onscroll = () => { if (flag) { return } flag = true setTimeout(()=>{ doSomething() flag = false }) }
Debounce示例
<input onKeyUp="kp()"> var timer var kp = ()=> { clearTimeout(timer) timer = setTimeout(()=> { search() }, 500) }