Web前端性能优化实践

1,061 阅读6分钟

Web前端性能优化实践

天下武功,唯快不破。

对于网站来说,怎么能给用户最快的响应、让用户有飞一般的体验是摆在每一名开发人员面前的难题。据研究表明,用户访问网站的时间体验尺度是以10为基数变化的,如果网站响应时间在0.1秒或更快,用户会感觉到他们的操作得到了“即时”的响应;如果响应时间超过0.1秒但不到1秒,虽然用户会感觉到短暂的延迟,但这感觉就像网站在给出反馈、与自己进行交互,是合理的时间延迟;如果响应时间超过1秒,用户就需要等待网站的回应,等待的时间越长,用户就越焦躁,大约10秒后,焦躁到极点,如果不是什么至关重要的网站,用户一般会选择放弃并愤怒地关掉网页。崔遥

因此无数开发人员前仆后继、夜以继日就为了能让网站提点速。然而这很难,因为网站性能的优化是一个非常庞大而复杂的课题,从前端到后端,各个层面都有很多技术难题要攻克。

本文将从前端角度,结合《高性能网站建设指南》一书中介绍的14条优化规则,在这里跟大家共同讨论一些前端优化的简单实践。

让我们先来思考并确定优化的方向,在很多书和文章中都提到了最为重要的两点:一是减少HTTP请求数量,二是减少响应内容的大小(即减少请求带宽)。如果能把这两点做好,问题也就解决一大半了。

减少HTTP请求数量

1

合并js、css等文件

浏览器同一时间针对同一域名下的请求有数量限制,超过限制数目的请求会被阻塞,不同浏览器限制数目不同,具体见下图。

因此在项目构建时,需要将js、css等文件按需进行合并,从而减少http请求数。在项目中,我们采用了RequreJS模块化工具,异步加载js模块,RequreJS官方配套的优化构建工具为r.js ,用于合并压缩脚本。

假设有两个页面Page1和Page2,Page1依赖模块A,B两个模块,Page2依赖B,C,D三个模块,而模块A和C又依赖模块E。

为r.js创建一个配置文件,进行一些最基本的配置。

r.js会自动追溯所有该模块的依赖模块,将其放进入口文件中。以上述配置为例,打出的dist包中,Page1.js中会包含模块A,B,E,Page2.js中会包含模块B,C,D,E。

我们还可以按照其他方式组织模块。


以上述配置为例,打出的dist包中会多出一个Common.js文件,包含A,B,C,D,E五个模块,而Page1.js和Page2.js中则不会包含任何依赖模块。

上面两种打包方法各有利弊,第一种方法:每个页面只需请求一个js文件即可加载出所有模块,但由于各个页面可能会依赖相同的模块,同一模块会被重复打入多个文件中,增加了总体dist包的大小,而且无法利用到浏览器的缓存。第二种方法:没有重复的模块,但第一次加载页面时需要加载两个js文件,虽然有些模块是第一个页面用不到的;但这种方式可以利用浏览器的缓存,将公共依赖文件Common.js缓存下来。

现在比较火的模块加载兼打包工具是webpack,功能更为强大,笔者也在学习中。

2

将图片制作成字体图标

网页上有很多零碎的图片,将它们整合到一起,可以极大减少图片的请求数。

字体图标(Icon Font),就是把图标做成字体,具有浏览器兼容性好、任意放大缩小、使用方便等特点。网上有很多漂亮的字体图标库,比如

Font Awesome (http://fontawesome.io/)

Foundation Icon Fonts (http://zurb.com/playground/foundation-icons)


MFG Labs Web Icon Set (http://mfglabs.github.io/mfglabs-iconset/)

IcoMoon (https://icomoon.io)


当然也可以定制自己的字体图标,在这里推荐IcoMoon网站,可以在线制作字体图标。具体方法为:首先通过AI或者PS制作矢量图标,输出成SVG格式。然后访问https://icomoon.io/app/#/select ,导入SVG格式的图标,即可生成对应的字体图标,包括style.css,eot压缩字库,整合后的svg图标,ttf字体,woff字体格式。

减少响应内容大小

1

压缩js、css文件和图片

压缩是去除代码中多余的空行和注释,减小文件大小。还可以配合代码混淆,将代码中的变量、函数、类的名字改写成无意义的名字,在保证功能的情况下,进一步精简。


我们采用Gulp作为打包构建工具,Gulp采用流式构建模式,没有中间文件生成,数据的读取和操作更快。Gulp有非常丰富的插件库,可以支持复杂的构建逻辑。下面以Gulp为例,配置各类文件压缩混淆任务。

2

开启服务器压缩

Nginx、Apache、IIS等Web服务器都支持Gzip压缩功能,可以将网页内容压缩后再传输到客户端,压缩率可达50%以上。以Nginx为例,可以进行如下配置: 

gzip on;

#开启,默认为off

gzip_min_length 10k;

#小于此值的数据包不会被压缩

gzip_buffers 16 8k;

#指定gzip压缩文件时向系统申请的缓存大小为16*8K

gzip_comp_level 2;

#gzip压缩级别,从1到9,级别越高压缩率越高但CPU占用率越高。

#实测发现,级别为2与9压缩后的文件大小基本相差无几,但CPU利用率相差却很大。

gzip_types text/plainapplication/javascript text/javascript application/x-javascriptapplication/json text/css text/xml application/xml;

#只有类型匹配的文件才会被压缩

gzip_vary on;

#在响应头中添加Vary: Accept-Encoding,告知代理服务器(如CDN服务器)客户端数据支持何种压缩方式

gzip_disable"MSIE[1-6]\.";

#IE6不支持压缩,不进行压缩

3

采用CDN

CDN全称为Content Delivery Network或者Content Distribute Network,即内容分发网络或内容交付网络,通过将服务内容分发至全网加速节点,用户访问站点时能够从就近节点获取所需内容,有效降低访问延迟,提升服务可用性。关于CDN的介绍网上有很多资料,在这里就不做搬运工了。

如果想用CDN,前端需要在打包构建时将html、css文件中引用静态资源的路径从相对路径修改为CDN域名下的绝对路径。

假如CDN域名为https://static.test.cn,那么在打包构建时,我们需要将上述文件中的相对路径修改为CDN域名下的绝对路径。使用Gulp 的cdnify插件,进行如下配置。

输出结果为:

参考资料:

https://www.nngroup.com/articles/powers-of-10-time-scales-in-ux/

https://developer.yahoo.com/performance/rules.html

http://www.stevesouders.com/blog/2008/03/20/roundup-on-parallel-connections/