域名"注册+交易+金融+行情+交流"
域名相关服务一应俱全,旨为您所想。

揭秘隐藏的网页加速秘籍:探索高效前端性能提升之道

如何提升前端性能优化

前端编程代码精简、易于维护、跨浏览器兼容性是至关重要的议题。从实际工程项目角度审视,最常见的前端性能优化问题。前端性能提升的基本规则,大体上包括了当前前端大部分的性能优化准则,众多更高级和细致的优化方法均源自这些原则。

前端性能提升的规则有哪些

1. 减少HTTP请求次数

2. 尽量合并图片、CSS、JS。例如,若页面包含5个CSS文件,将其合并为一个,则仅需发起一次HTTP请求,节省网络请求时间,加快页面加载速度。

3. 使用CDN

4. 避免空的src和href

5. 为文件头指定过期时间

6. 使用gzip压缩内容

7. 把CSS放到顶部

8. 把JS放到底部

9. 避免使用CSS表达式

10. 将CSS和JS放到外部文件中

11. 权衡DNS查找次数

12. 精简CSS和JS

13. 避免跳转

14. 删除重复的JS和CSS

15. 配置ETags

16. 可缓存的AJAX

17. 使用GET来完成AJAX请求

18. 减少DOM元素数量

19. 避免404

20. 减少Cookie的大小

21. 使用无cookie的域

22. 不要使用滤镜

IE独有的属性AlphaImageLoader用于纠正7.0以下版本中展示PNG图片的半透明效果。此滤镜的缺陷在于浏览器加载图片时它会中断内容的展示并且使浏览器停滞。在每一个元素(不仅仅是图片)它都会运算一次,增加了内存消耗,因此它的问题是多方面的。

完全摒弃使用AlphaImageLoader的最佳方法就是使用PNG8格式来替代,这种格式能在IE中很好地运行。如果你确实需要使用AlphaImageLoader,请使用下划线_filter又使之对IE7以上版本的用户无效。

22.不要在HTML中放大图片

比如你需要的图片尺寸是50 50

那就不用用一张500500的大尺寸图片,影响加载

23.缩小favicon.ico并缓存

常见的前端性能提升手段都有哪些及其收益

前端是庞大的,包括 HTML、 CSS、 Javascript、Image、Flash等等各种各样的资源。前端优化是复杂的,针对各个方面的资源都有不同的方法。那么,前端优化的目的是什么?

1.从用户角度而言,优化能够让页面加载得更快、对用户的操作响应得更迅速,能够给用户提供更为友好的体验。

2.从服务商角度而言,优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。

总之,恰当的优化不仅能够提升站点的用户体验并且能够节省相当的资源利用。

前端优化的途径有很多,按粒度大致可以分为两类,第一类是页面级别的优化,例如 HTTP请求数、脚本的无阻塞加载、内联脚本的位置优化等;第二类则是代码级别的优化,例如 Javascript中的DOM操作优化、CSS选择符优化、图片优化以及 HTML结构优化等等。另外,本着提高投入产出比的目的,后文提到的各种优化策略大致按照投入产出比从大到小的顺序排列。

一、页面级优化

1.降低 HTTP请求数

这条策略基本上所有前端人都知道,而且也是最重要最有效的。都说要降低 HTTP请求,那请求多了到底会怎么样呢?首先,每个请求都是有成本的,既包含时间成本也包含资源成本。一个完整的请求都需要经过 DNS寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据这样一个“漫长”而复杂的过程。时间成本就是用户需要看到或者“感受”到这个资源是必须要等待这个过程结束的,资源上由于每个请求都需要携带数据,因此每个请求都需要占用带宽。另外,由于浏览器进行并发请求的请求数是有上限的(具体参见此处),因此请求数多了以后,浏览器需要分批进行请求,因此会增加用户的等待时间,会给用户造成站点速度慢这样一个印象,即使可能用户能看到的第一屏的资源都已经请求完了,但是浏览器的进度条会一直存在。

降低 HTTP请求数的主要途径包括:

(1).从设计实现层面简化页面

如果你的页面像百度首页一样简单,那么接下来的规则基本上都用不着了。保持页面简洁、减少资源的使用时最直接的。如果不是这样,你的页面需要华丽的皮肤,则继续阅读下面的内容。

(2).合理设置 HTTP缓存

缓存的力量是强大的,恰当的缓存设置可以大大的降低 HTTP请求。以有啊首页为例,当浏览器没有缓存的时候访问一共会发出 78个请求,共 600多 K数据(如图 1.1),而当第二次访问即浏览器已缓存之后访问则仅有 10个请求,共 20多 K数据(如图 1.2)。(这里需要说明的是,如果直接 F5刷新页面的话效果是不一样的,这种情况下请求数还是一样,不过被缓存资源的请求服务器是 304响应,只有 Header没有Body,可以节省带宽)

怎样才算合理设置?原则很简单,能缓存越多越好,能缓存越久越好。例如,很少变化的图片资源可以直接通过 HTTP Header中的Expires设置一个很长的过期头;变化不频繁而又可能会变的资源可以使用 Last-Modifed来做请求验证。尽可能的让资源能够在缓存中待得更久。关于 HTTP缓存的具体设置和原理此处就不再详述了,有兴趣的可以参考下列文章:

HTTP1.1协议中关于缓存策略的描述

Fiddler HTTP Performance中关于缓存的介绍

(3).资源合并与压缩

如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外, CSS、 Javascript、Image都可以用相应的工具进行压缩,压缩后往往能省下不少空间。

(4). CSS Sprites

合并 CSS图片,降低请求数的又一个好办法。

(5). Inline Images

使用 data: URL scheme的方式将图片嵌入到页面或 CSS中,如果不考虑资源管理上的问题的话,不失为一个好办法。如果是嵌入页面的话换来的是增大了页面的体积,而且无法利用浏览器缓存。使用在 CSS中的图片则更为理想一些。

(6). Lazy Load Images(自己对这一块的内容还是不了解)

这条策略实际上并不一定能降低 HTTP请求数,但是却能在某些条件下或者页面刚加载时降低 HTTP请求数。对于图片而言,在页面刚加载的时候可以只加载第一屏,当用户继续往后滚屏的时候才加载后续的图片。这样一来,假如用户只对第一屏的内容感兴趣时,那剩余的图片请求就都节省了。有啊首页曾经的做法是在加载的时候把第一屏之后的图片地址缓存在 Textarea标签中,待用户往下滚屏的时候才“惰性”加载。

2.将外部脚本置底(将脚本内容在页面信息内容加载后再加载)

前文有谈到,浏览器是可以并发请求的,这一特点使得其能够更快的加载资源,然而外链脚本在加载时却会阻塞其他资源,例如在脚本加载完成之前,它后面的图片、样式以及其他脚本都处于阻塞状态,直到脚本加载完成后才会开始加载。如果将脚本放在比较靠前的位置,则会影响整个页面的加载速度从而影响用户体验。解决这一问题的方法有很多,在这里有比较详细的介绍(这里是译文和更详细的例子),而最简单可依赖的方法就是将脚本尽可能的往后挪,减少对并发下载的影响。

前文已有提及,浏览器具备并发请求的能力,这一特性使其能更迅速地加载资源。但外部脚本在加载过程中会阻碍其他资源,比如在脚本加载完毕前,其后的图片、样式及脚本等均处于停滞状态,直至脚本加载完毕才重新启动。若将脚本置于页面前端,将影响整体加载速度,进而影响用户体验。针对这一问题,有多种解决方案,本文将详细阐述(此处为译文及更详尽的示例),其中最简便且可靠的方法是将脚本尽可能后移,以降低对并发下载的影响。

  1. 异步执行内联脚本(其原理与上文所述相同,确保脚本在页面内容之后加载。)

    内联脚本对性能的影响不亚于外部脚本。首先,与外部脚本类似,内联脚本在执行时同样会阻塞并发请求。其次,由于浏览器在页面处理方面是单线程的,当内联脚本在页面渲染前执行时,页面渲染工作将被推迟。简言之,内联脚本执行期间,页面处于空白状态。鉴于以上两点原因,建议将执行时间较长的内联脚本异步执行。异步执行方式有多种,例如使用script元素的defer属性(存在兼容性问题及其他问题,如不能使用document.write)、使用setTimeout。此外,HTML5中引入的Web Workers机制恰好可以解决此类问题。

  2. 懒加载JavaScript(仅在需要加载时加载,一般情况下不加载信息内容。)

    随着JavaScript框架的普及,越来越多的网站开始采用框架。然而,一个框架通常包含许多功能实现,并非每个页面都需要这些功能。若下载了不必要的脚本,则相当于浪费了带宽和执行时间。目前,有两种做法:一种是为流量大的页面定制专用的mini版框架;另一种则是懒加载。YUI就采用了第二种方式,在YUI的实现中,最初只加载核心模块,其他模块可在需要时加载。

  3. 将CSS置于HEAD中

    若将CSS置于BODY中,则浏览器可能在下载和解析CSS之前就开始渲染页面,导致页面从无CSS状态跳转到CSS状态,用户体验较差。此外,一些浏览器会在CSS下载完毕后才开始渲染页面,若CSS放置于页面下方,则会导致浏览器推迟渲染时间。

  4. 异步请求回调(将部分行为样式提取出来,逐步加载信息内容)

    在某些页面中,可能需要使用script标签异步请求数据。例如:

javascript

function myCallback(info){

//执行操作

}

html

cb返回的内容: myCallback('Hello world!');

以上方式直接在页面上编写标签对页面性能也有影响,增加了页面首次加载的负担,推迟了DOMLoaded和window.onload事件的触发时机。若时效性允许,可以考虑在DOMLoaded事件触发时加载,或使用setTimeout灵活控制加载时机。

  1. 减少不必要的HTTP跳转

    对于以目录形式访问的HTTP链接,许多人会忽略链接末尾是否带有'/'。若服务器对此有所区分,则需注意,这可能导致301跳转,增加多余请求。具体可参考下图,其中第一个链接以无'/'结尾的方式访问,服务器因此进行了一次跳转。

  2. 避免重复的资源请求

    这种情况主要由于疏忽或页面由多个模块拼接而成,导致每个模块请求相同的资源,从而产生重复请求。

二、代码级优化

1. JavaScript

(1). DOM

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

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

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

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

b. Reflow & Repaint

除了上述一点,DOM操作还需考虑浏览器的Reflow和Repaint,因为这些都是需要消耗资源的。具体可参考以下文章:

如何减少浏览器的repaint和reflow?

Understanding Internet Explorer Rendering Behaviour

Notes on HTML Reflow

(2).慎用with

with(obj){ p= 1};代码块的行为实际上是修改了代码块中的执行环境,将obj放在了其作用域链的最前端。在with代码块中访问非局部变量时,都是先从obj上开始查找,如果没有再依次按作用域链向上查找。因此,使用with相当于增加了作用域链长度。而每次查找作用域链都会消耗时间,过长的作用域链会导致查找性能下降。

因此,除非你能确定在with代码中只访问obj中的属性,否则慎用with。替代方案是使用局部变量缓存需要访问的属性。

因此,除非你确信在 with代码中仅访问 obj中的属性,否则请谨慎使用with,可以用局部变量来保存需要访问的属性来替代。

(3). 避免使用eval和Function

每次eval或Function构造函数对字符串形式的源代码进行操作时,脚本引擎都需要将其转换成可执行代码。这是一个非常耗费资源的操作——通常比简单的函数调用慢100倍以上。

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

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

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

(4). 减少作用域链查找(这涉及到一些相关内容的问题)

前文提到了作用域链查找问题,这一点在循环中尤其需要注意。如果在循环中需要访问非本作用域下的变量时,请在遍历之前用局部变量保存该变量,并在遍历结束后再修改那个变量,这一点对全局变量尤其重要,因为全局变量处于作用域链的最顶端,访问时的查找次数是最多的。

低效的写法:

//全局变量

var globalVar = 1;

function myCallback(info){

for(var i = 100000; i--;){

//每次访问globalVar都需要查找到作用域链最顶端,本例中需要访问100000次

globalVar += i;

}

}

更高效的写法:

//全局变量

var globalVar = 1;

function myCallback(info){

//局部变量保存全局变量

var localVar = globalVar;

for(var i = 100000; i--;){

//访问局部变量是最快的

localVar += i;

}

//本例中只需要访问2次全局变量

在函数中只需要将globalVar中内容的值赋给localVar中

globalVar = localVar;

}

此外,要减少作用域链查找还应减少闭包的使用。

(5). 数据访问

JavaScript中的数据访问包括直接量(字符串、正则表达式)、变量、对象属性以及数组,其中对直接量和局部变量的访问是最快的,对对象属性以及数组的访问需要更大的开销。当出现以下情况时,建议将数据放入局部变量:

a. 对任何对象属性的访问超过1次

b. 对任何数组成员的访问次数超过1次

另外,还应当尽可能减少对对象以及数组深度查找。

(6). 字符串拼接

在JavaScript中使用"+"号来拼接字符串效率较低,因为每次运行都会开辟新的内存并生成新的字符串变量,然后将拼接结果赋值给新变量。与之相比,更高效的做法是使用数组的join方法,即将需要拼接的字符串放在数组中,最后调用其join方法得到结果。不过由于使用数组也有一定的开销,因此当需要拼接的字符串较多的时候可以考虑使用此方法。

关于JavaScript优化的更详细介绍请参考:

Write Efficient JavaScript(PPT)

Efficient JavaScript

  1. CSS选择符

    在大多数人的观念中,都觉得浏览器对CSS选择符的解析是从左往右进行的,例如

toc A{ color:#444;}

这样一个选择符,如果是从右往左解析则效率会很高,因为第一个ID选择基本上就把查找的范围限定了,但实际上浏览器对选择符的解析是从右往左进行的。如上面的选择符,浏览器必须遍历查找每一个A标签的祖先节点,效率并不像之前想象的那样高。根据浏览器的这一行为特点,在写选择符的时候需要注意很多事项,有人已经一一列举了,详情参考此处。

  1. HTML

    对HTML本身的优化现如今也越来越多地受到人们的关注,详情可以参见这篇总结性文章。

  2. Image压缩

    图片压缩是一项技术活,不过现如今这方面的工具也非常多,压缩之后往往能带来不错的效果,具体的压缩原理以及方法在《Even Faster Web Sites》第10章有很详细的介绍,有兴趣的可以去看看。

总结

本文从页面级以及代码级两个层面总结了前端优化的各种方式,这些方法基本上都是前端开发人员在开发过程中可以借鉴和实践的。除此之外,完整的前端优化还应包括很多其他的途径,例如CDN、Gzip、多域名、无Cookie服务器等等,由于对于开发人员的可操作性并不强,在此也就不多叙述了,详细的可以参考Yahoo和Google的这些“金科玉律”。

以上所转载内容均来自于网络,不为其真实性负责,只为传播网络信息为目的,非商业用途,如有异议请及时联系btr2020@163.com,本人将予以删除。夫唯域名网 » 揭秘隐藏的网页加速秘籍:探索高效前端性能提升之道

分享到: 生成海报