你不知道的前端性能优化 - 静态资源优化 (一)
前言:所有的优化点都有其适用的条件,所有的优化点都能够量化看到效果,具体项目具体分析,并不是每个项目都能适用这里的每个点,望周知。
目录
- 资源合并与压缩
- 图片相关
- 使用不同的图片格式
- 使用雪碧图和svg
- 懒加载和预加载
- 小图片使用base64
- 浏览器加载
html
- 浏览器输入网址敲击回车之后发生了什么?
静态资源
-
资源的合并与压缩
这里主要针对的是js
、css
、html
-
资源合并
资源合并是指将多个文件合并到一个文件。主要优化点是减少网页的http
请求,以此来达到优化目的。
方法有很多,比如我们可以使用构建工具进行合并等。 -
资源压缩
资源压缩是指将单个文件进行压缩。主要的优化点是减小文件的大小,以此来达到优化的目的。
方法同样有很多,比如打包的使用gzip
或者服务器开启gzip
。
你可以使用
chrome
的测试查看压缩和未压缩之间的请求读取时间。 -
资源合并
-
图片相关
-
使用不同的图片格式
不同的图片格式对应着不同的适用场景,我们可以通过不同格式间的差别来选择不同的图片格式,达到最佳的适用范围。
jpg png8 png24 png32 webp 有损压缩 无损压缩 无损压缩 无损压缩 支持有损压缩和无损压缩 图片的品质会有变化,压缩品质设置在60-80时肉眼很难鉴别 只能索引256 (2^8)种颜色 能索引近1600万 (2^24)种颜色 能索引(2^32)很多种颜色 Alpha 透明和 24-bit 颜色数 适合大块颜色相近的图片,颜色较少的图片和写实的图片可以使用 颜色较少的图片情况下可以使用 颜色较多,比较常用的图片格式 颜色很多,适用于需要使用高清的图片场景 现代化浏览器和Android 支持Alpha透明和索引色透明 不支持透明(ps导出透明png24时,其实转化成png32) 支持透明和半透明呢 支持透明和半透明 轮播图、头像等 小图标 背景图 高清海报等 webp 是由谷歌发展出来的图片的格式,它具有更高的压缩率、同时支持无损和有损压缩、色彩丰富和比 png 更优的解码速度的优点。我估计 webp 在未来可能会替代 png。
webp 同时也具有兼容性的缺点,只有现代化浏览器和是 Chromium 内核的浏览器天生支持 webp。ios并不原生支持 webp, Safari也不支持webp,并且没有要支持 webp 的消息。在 Android 上从 Android 4.0 开始才原生支持 webp。所以谷歌官方提供了 webp 的解析库 (Android、iOS)。
- 使用雪碧图和svg
-
懒加载和预加载
- 懒加载
这是一种常见的前端提升响应速度的一张方式,对于图片数量较多的情况下,只展示可视区域的图片,当一张图片在可视区域内才去请求该图片的真实资源,默认显示一张加载图片。这样可以保证性能的最大化。 常用的懒加载库有基于 jQuery 的lazyload
,vue 的vue-lazyload
各大框架都有不同的实现库。 - 预加载(不仅仅针对图片资源)
预加载也是一种常见的前端,速度优化方式,用于提高页面的响应速度。实现有很多种方式,可以使用:异步请求,html标签和 new Image() 的方式等。可以使用 proload。
- 懒加载
-
小图片使用base64
- 在项目中,对于一些像 icon 这样的小图标如果它是图片实现的,我们其实可以使用 base64 直接引入。这样做有什么好处呢?它能减少
http
请求,从而达到优化。 - 大图片并不推荐使用 base64 直接引入,因为图片转换成 base64 后往往存储会变大,比如你本来的图片是 3m 那么你转成 base64 后的编码可能会有 3.9m 的样子。
- 图片转化这里,如果项目使用了 webpack 打包的话,对
url-loader
的limit
配置改改就能打包
的时候实现转化了。
- 在项目中,对于一些像 icon 这样的小图标如果它是图片实现的,我们其实可以使用 base64 直接引入。这样做有什么好处呢?它能减少
-
使用不同的图片格式
浏览器加载html与执行
是不是听过这样一个问题:浏览器输入网址敲击回车之后发生了什么?
发生了什么呢?
- 浏览器首先会请求该
url
地址。 - 获取到
html
后进行 由上至下解析。 - 解析到
<link>
标签请求css
,会异步的请求该css
- 解析到普通的
dom
的时候,会先在内存中生成对应的dom tree
- 请求到相应的
css
的时候会在内存中生成对应的cssom
- 当解析到
<script>
标签的时候,分三种情况(js
的执行会阻塞dom
的解析):- 如果标签带了
defer
属性:该<script>
标签后面的内容继续加载,并异步的请求该<script>
的内容,执行需要等待到DOMContentLoaded
事件触发后才执行,也就是dom
解析完之后执行。 - 如果标签带了
async
属性:该<script>
标签后面的内容继续加载,并异步的请求该<script>
的内容,请求完成后立即执行该<script>
的内容,此时不管html parser
(html 解析器) 有没有完成,直接阻塞。 - 如果标签内没有带
async
和defer
属性:那么请求的过程会直接阻塞html parser
的执行,请求完后会立即执行,执行的过程也会阻塞html parser
。
- 如果标签带了
- 当
html parser
完成后,也就是dom tree
和cssom
都加载完毕后,会进入到render tree
的过程,就是把dom tree
和cssom
结合渲染的过程。 - 当
render tree
渲染完成后,会进入到layout
布局的一个过程。 - 当
layout
完成后,就会进入到paint
绘制的一个过程。 -
paint
绘制完成后,此时整个页面就加载完成了。

第六点中要注意的是 使用外部样式会阻塞后续脚本执行但不会阻塞其的加载。
我们可以从这整个 html
的渲染流程种的每一步寻找优化点,当页面加载的时候遇到 <script>
标签会阻塞 html parser
,所以我们将 <script>
标签放到 <body>
内不放到 <head>
中 我们需要用户先看到页面的基本内容的体验。
render tree
后先是进行了 layout
和 paint
这两个过程,而我们之后会频繁的修改 dom
,修改后每次都需要进行 layout
和 paint
的过程吗?这里有没有优化点呢?
本文章由作者自学完前端性能优化后的自述,如有不正 欢迎大佬们在评论席交流指点。
其它篇幅传送门:
网友评论