程序猿进阶路上不能错过之最全前端性能优化秘籍(二)!

周智星
5671     

上一章节中,我们提到了页面级别的优化前端性能,本章节,我们会继续详细介绍另外两类的优化:服务端优化和代码级优化。


【服务器端优化】
一、使用CDN
再次强调第一条黄金定律,减少网页内容的下载时间。提高下载速度还可以通过CDN(内容分发网络)来提升。CDN通过部署在不同地区的服务器来提高客户的下载速度。如果你的网站上有大量的静态内容,世界各地的用户都在访问,那CDN是必不可少的。事实上大多数互联网中的巨头们都有自己的CDN。网站可以先通过免费的CDN供应商来分发网页资源。

二、添加Expires 或Cache-Control报文头
对于站点中不经常修改的静态内容(如图片,JS,CSS),可以在服务器中设置expires过期时间,控制浏览器缓存,达到有效减小带宽流量,降低服务器压力的目的。


 代码示例:

Expires是Web服务器响应消息头字段,在响应http请求时告诉浏览器在过期时间前浏览器可以直接从浏览器缓存取数据,而无需再次请求。


Cache-control策略
Cache-Control与Expires的作用一致,都是指明当前资源的有效期,控制浏览器是否直接从浏览器缓存取数据还是重新发请求到服务器取数据。只不过Cache-Control的选择更多,设置更细致,如果同时设置的话,其优先级高于Expires。http协议头Cache-Control值可以是public、private、no-cache、no- store、no-transform、must-revalidate、proxy-revalidate、max-age。


各个消息中的指令含义如下:
▪ Public指示响应可被任何缓存区缓存。

▪ Private指示对于单个用户的整个或部分响应消息,不能被共享缓存处理。这允许服务器仅仅描述当用户的部分响应消息,此响应消息对于其他用户的请求无效。

▪ no-cache指示请求或响应消息不能缓存。

▪ no-store用于防止重要的信息被无意的发布。在请求消息中发送将使得请求和响应消息都不使用缓存。

▪ max-age指示客户机可以接收生存期不大于指定时间(以秒为单位)的响应。

▪ min-fresh指示客户机可以接收响应时间小于当前时间加上指定时间的响应。

▪ max-stale指示客户机可以接收超出超时期间的响应消息。如果指定max-stale消息的值,那么客户机可以接收超出超时期指定值之内的响应消息。


三、Gzip压缩传输文件
Gzip通常可以减少70%网页内容的大小,包括脚本、样式表、图片等文件。Gzip比deflate更高效,主流服务器都有相应的压缩支持模块。


IIS中内建了静态压缩和动态压缩模块,如何配制可以参考Enable HTTP Compression of Static Content (IIS 7)和Enable HTTP Compression of Dynamic Content (IIS 7)。值得注意的是pdf文件可以从需要被压缩的类型中剔除,因为pdf文件本身已经压缩,gzip对其效果不大,而且会浪费CPU。大概配置如下:


1.Vim打开Nginx配置文件
vim /usr/local/nginx/conf/nginx.conf

2.找到如下一段,进行修改

3.解释一下
第1行:开启Gzip。
第2行:不压缩临界值,大于1K的才压缩,一般不用改。
第3行:buffer,不用改。
第4行:用了反向代理的话,末端通信是HTTP/1.0,有需求的应该也不用看我这科普文了;有这句的话注释了就行了,默认是HTTP/1.1。
第5行:压缩级别,1-10,数字越大压缩的越好,时间也越长,看心情随便改吧。
第6行:进行压缩的文件类型,缺啥补啥就行了,JavaScript有两种写法,最好都写上吧,总有人抱怨js文件没有压缩,其实多写一种格式就行了。
第7行:跟Squid等缓存服务有关,on的话会在Header里增加"Vary: Accept-Encoding",我不需要这玩意,自己对照情况看着办吧。
第8行:IE6对Gzip不怎么友好,不给它Gzip了。


四、配置ETags
虽然标题叫配制ETags,但是这里你要根据具体情况进行一些判断。首先Etag简单来说是通过一个文件版本标识使得服务器可以轻松判断该请求的内容是否有所更新,如果没有就回复304 (not modified),从而避免下载整个文件。


但是Etags的版本信息即使主流服务器未能很好地支持跨服务器的判断,比如你从一个服务器集群中一台得到Etags,然后发送到了另一台那么校验很有可能会失败。


【代码级优化】
一、DOM

DOM操作应该是脚本中最耗性能的一类操作,例如增加、修改、删除 DOM元素或者对 DOM集合进行操作。如果脚本中包含了大量的 DOM操作则需要注意以下几点:


HTML Collection(HTML收集器,返回的是一个数组内容信息)

在脚本中 document.images、document.forms 、getElementsByTagName()返回的都是 HTMLCollection类型的集合,在平时使用的时候大多将它作为数组来使用,因为它有 length属性,也可以使用索引访问每一个元素。不过在访问性能上则比数组要差很多,原因是这个集合并不是一个静态的结果,它表示的仅仅是一个特定的查询,每次访问该集合时都会重新执行这个查询从而更新查询结果。所谓的 “访问集合” 包括读取集合的 length属性、访问集合中的元素。


因此,当你需要遍历 HTML Collection的时候,尽量将它转为数组后再访问,以提高性能。即使不转换为数组,也请尽可能少的访问它,例如在遍历的时候可以将 length属性、成员保存到局部变量后再使用局部变量。

二、避免全局查找
在一个函数中会用到全局对象存储为局部变量来减少全局查找,因为访问局部变量的速度要比访问全局变量的速度更快些,如图:


三、避免使用 eval和 Function
每次 eval 或 Function 构造函数作用于字符串表示的源代码时,脚本引擎都需要将源代码转换成可执行代码。这是很消耗资源的操作 —— 通常比简单的函数调用慢 100倍以上。


eval 函数效率特别低,由于事先无法知晓传给 eval 的字符串中的内容,eval在其上下文中解释要处理的代码,也就是说编译器无法优化上下文,因此只能有浏览器在运行时解释代码。这对性能影响很大。


Function 构造函数比 eval略好,因为使用此代码不会影响周围代码 ;但其速度仍很慢。


此外,使用 eval和 Function也不利于Javascript 压缩工具执行压缩。


四、尽量减少循环次数
少一层循环,就能提高数倍性能。如果要对一个数组的每个元素进行多次操作,尽可能使用一次循环,多次操作,而不是多次循环,每次循环执行一次操作。尤其是在进行多个正则匹配的时候,尽可能合并正则表达式,在一次遍历中尽可能找到相应的匹配,如下图:

Switch


【总结】
本文从页面级、服务器以及代码级三个粒度对前端优化的各种方式做了一个总结,这些方法基本上都是前端开发人员在开发的过程中可以借鉴和实践的,除此之外,完整的前端优化还应该包括很多其他的途径,例如 CDN、 Gzip、多域名、无 Cookie服务器等等。


  参考文献:

《高性能网站建设指南》
《高性能网站建设进阶指南》

未经授权禁止转载,详情见转载须知

联系我们

恒 生 技 术 之 眼