前端性能优化-工程化能做的
随着业务越来越复杂,前端项目越来越多庞大,性能优化是一个绕不过去的大问题。或多或少,我们在开发中应该都遇到过。
# 已有的实践原则
实际上很早之前,就已经有两本指导性著作来探讨这个问题《高性能网站建设指南》、《高性能网站建设进阶指南》,还有雅虎14条 (opens new window)性能优化原则。
- 尽可能的减少 HTTP 的请求数 (content)
- 使用 CDN(Content Delivery Network) (server)
- 添加 Expires 头(或者 Cache-control ) (server)
- Gzip 组件 (server)
- 将 CSS 样式放在页面的上方 (css)
- 将脚本移动到底部(包括内联的) (javascript)
- 避免使用 CSS 中的 Expressions (css)
- 将 JavaScript 和 CSS 独立成外部文件 (javascript) (css)
- 减少 DNS 查询 (content)
- 压缩 JavaScript 和 CSS (包括内联的) (javascript) (css)
- 避免重定向 (server)
- 移除重复的脚本 (javascript)
- 配置实体标签(ETags) (css)
- 使 AJAX 缓存
不过随着技术,工程的演进,项目中有一些已经变成标配。我们来挨个细究下。
根据这两本指导书和雅虎14条我们可总结整理如下表格。
优化方向 | 优化手段 |
---|---|
请求数量 | 合并脚本和样式表,CSS Sprites,拆分初始化负载,划分主域 |
请求带宽 | 开启GZip,精简JavaScript,移除重复脚本,图像优化 |
缓存利用 | 使用CDN,使用外部JavaScript和CSS,添加Expires头, |
减少DNS查找 | 配置ETag,使AjaX可缓存 |
页面结构 | 将样式表放在顶部,将脚本放在底部 |
代码校验 | 避免CSS表达式,避免重定向 |
我们可以看出来,这些大部分是工程问题,既然是工程问题,那么我们就用工程化来解决。
# webpack工程化能解决的
# 合并脚本和样式表,拆分初始化负载
webpack作为强大灵活的打包构建工具,可以将各个模块文件通过配置以及规则整合到一起,并可以按需合理拆分按需加载。
# CSS Sprites 或 行内图片
把常用的图标合并成css sprite(雪碧图),可以有效的减少站点的http请求数量,从而提高网站性能 CSS Sprites (opens new window) 行内图片(Base64 编码)小图标图片可以通过webpack插件自动转为base64编码的图片嵌入 HTML 或者 CSS 中。也可以减少请求数量。
# 使用字体图标 iconfont 代替图片图标
字体图标就是将图标制作成一个字体,使用时就跟字体一样,可以设置属性,例如 font-size、color 等等,非常方便。并且字体图标是矢量图,不会失真。还有一个优点是生成的文件特别小。
# 精简Javascript及css
借助webpack的插件 轻松将js,css,html压缩,减小文件的体积。
- JavaScript:UglifyPlugin
- CSS :MiniCssExtractPlugin
- HTML:HtmlWebpackPlugin
服务端开启gzip也强力推荐,一般可以减少20%至30%的体积,效果立竿见影。
# 移除重复脚本
这一条目前已经不太适用了,现在项目开发大都以模块化,工程化管理,配合git这种版本管理工具,重复脚本的粒度已经可以控制到比较小的程度,已经不再属于工程问题,而是开发问题了。 另外利用 ES2015 模块系统中的静态结构特性,例如 import 和 export,还可以通过静态分析,去除未使用的模块或函数,做到更进一步的精简。
# 使用CDN
使用CDN实现静态资源的缓存和快速访问。
# 添加Expires头 配置ETag
通过webpack打包,文件可设置指纹,那么bundle模块可以设置为永久强制缓存,覆盖发布,如果文件没有更新,指纹hash将不会变化,即可做到缓存且不影响覆盖部署时的更新问题。
# 将样式表放在顶部,将脚本放在底部
head 标签里的 CSS 和 JS 文件都会堵塞渲染(CSS 不会阻塞 DOM 解析)。如果这些 CSS 和 JS 需要加载和解析很久的话,白屏时间就很长。所以 JS 文件要放在底部,等 HTML 解析完了再加载 JS 文件。 那为什么 CSS 文件还要放在头部呢? 因为先加载 HTML 再加载 CSS,会让用户第一时间看到的页面是没有样式的,为了避免这种情况发生,就要将 CSS 文件放在头部了。 另外,JS 文件也不是不可以放在头部,只要给 script 标签加上 defer 属性就可以了,异步下载,延迟执行。
webpack的html模版插件可以自动处理。
# 避免CSS表达式
如果你不了解CSS表达式,那么恭喜你,你不需要再了解它了。这个功能因为性能问题已经不再被支持了。