前端性能优化总结

 

前端性能优化的目的: 
1. 从用户角度而言:优化能够让页面加载得更快、对用户的操作响应的更及时,能够给用户提供更为良好的体验。 
2. 从服务商角度而言:优化能够减少页面请求数、或者减小请求所占带宽,能够节省可观的资源。

一:减少HTTP请求

  在浏览器(客户端)和服务器发生通信时,就已经消耗了大量的时间,尤其是在网络情况比较糟糕的时候,这个问题尤其的突出。 
  一个正常HTTP请求的流程简述:如在浏览器中输入”www.xxxxxx.com”并按下回车,浏览器再与这个URL指向的服务器建立连接,然后浏览器才能向服务器发送请求信息,服务器在接受到请求的信息后再返回相应的信息,浏览器接收到来自服务器的应答信息后,对这些数据解释执行。
   HTTP协议是无状态的应用层协议,意味着每次HTTP请求都需要建立通信链路、进行数据传输,当我们请求的网页文件中有很多图片、CSS、JS甚至音乐等信息时,将会频繁的与服务器建立连接并释放连接,这必定会造成资源的浪费,而在服务端,每个HTTP都需要启动独立的线程去处理,这些通信和服务的开销都很昂贵,每个HTTP请求都会对服务器和浏览器产生性能负担。
   网速相同的条件下,下载一个100KB的图片比下载两个50KB的图片要快。

通常手段有

⑴  合并文件(合并CSS、合并js、合并图片
将浏览器一次访问需要的JavaScript、CSS合并成一个文件,这样浏览器只需要一次请求。

图片也可以合成,多张图片合并成一张,如果每张图片都有不同的超链接,可通过CSS偏移响应鼠标点击操作,构造不同的URL。

⑵   CSS Sprites
将多张背景图合并成一张,并且通过background-position属性值来确定图片呈现的位

⑶   Lazy Load Images  懒加载
它的核心思想是:当用户想看页面某个区域时,再加载该区域的数据。这在一定程度上减轻了服务器端的压力,也加快了页面的呈现速度。

   ①例如:原来的图片为<img src="xxx.jpg" />,现在改为<img data-src="xxx.jpg">。这样,页面在解析的时候,所有懒加载的图片在所有的浏览器下都不会下载,图片进入视野区域时再将data-src赋值给src属性。

    ② 提供延迟加载页面模块的方案。将研究发现,textarea是个不错的容器,浏览器会将该标签内的内容当作普通文本看待。因此,可以将页面中需要懒加载的模块放入textarea容器中,带需要的时候再将其取出。

 

⑷ 使用浏览器缓存

  对一个网站而言,CSS、JavaScript、Logo、图标这些静态资源文件更新的频率都比较低,而这些文件又几乎是每次HTTP请求都需要的,如果将这些文件缓存在浏览器中,可以极好地改善性能。通过设置HTTP头中的Cache-Control和Expires属性,可设定浏览器缓存,缓存时间可以是数天,甚至是数月。 
  在某些时候,静态资源文件变化需要及时应用到客户端浏览器,这种情况,可以通过改变文件名实现 ,即更新JavaScript文件并不是更新JavaScript文件内容,而是生成新的JS文件并更新HTML文件中的引用。
  使用浏览器缓存策略的网站在更新静态资源时,应采用分批次更新的方法,比如需要更新10个图标文件,不宜把10个文件一次全部更新,而应该一个文件一个文件逐步更新,并有一定的间隔时间,以免用户浏览器突然大量缓存失效,集中更新缓存,造成服务器负载骤增,网络堵塞的情况。   

二:减少DNS查找次数(DNS缓存)
基础知识

DNS(Domain Name System): 负责将域名URL转化为服务器主机IP。

DNS查找流程:首先查看浏览器缓存是否存在,不存在则访问本机DNS缓存,再不存在则访问本地DNS服务器。所以DNS也是开销,通常浏览器查找一个给定URL的IP地址要花费20-120ms,在DNS查找完成前,浏览器不能从host那里下载任何东西。

TTL(Time To Live):表示查找返回的DNS记录包含的一个存活时间,过期则这个DNS记录将被抛弃。

当客户端的DNS缓存为空时,DNS查找的数量与Web页面中唯一主机名的数量相等。所以减少唯一主机名的数量就可以减少DNS查找的数量。

然而减少唯一主机名的数量会潜在地减少页面中并行下载的数量,避免DNS查找降低了响应时间,但减少并行下载可能会增加响应时间。当页面的组件量比较多的时候,可以考虑将组件分别放到至少2-4个主机名,已获得最大收益。


三、避免重定向

二、避免重定向

什么是重定向?

重定向用于将用户从一个URL重新路由到另一个URL。

常用重定向的类型

301:永久重定向,主要用于当网站的域名发生变更之后,告诉搜索引擎域名已经变更了,应该把旧域名的的数据和链接数转移到新域名下,从而不会让网站的排名因域名变更而受到影响。

302:临时重定向,主要实现post请求后告知浏览器转移到新的URL。

304:Not Modified,主要用于当浏览器在其缓存中保留了组件的一个副本,同时组件已经过期了,这是浏览器就会生成一个条件GET请求,如果服务器的组件并没有修改过,则会返回304状态码,同时不携带主体,告知浏览器可以重用这个副本,减少响应大小。

重定向如何损伤性能?

当页面发生了重定向,就会延迟整个HTML文档的传输。在HTML文档到达之前,页面中不会呈现任何东西,也没有任何组件会被下载。

来看一个实际例子:对于ASP.NET webform开发来说,对于新手很容易犯一个错误,就是把页面的连接写成服务器控件后台代码里,例如用一个Button控件,在它的后台click事件中写上:Response.Redirect("");然而这个Button的作用只是转移URL,这是非常低效的做法,因为点击Button后,先发送一个Post请求给服务器,服务器处理Response.Redirect("")后就发送一个302响应给浏览器,浏览器再根据响应的URL发送GET请求。正确的做法应该是在html页面直接使用a标签做链接,这样就避免了多余的post和重定向。

重定向的应用场景

1. 跟踪内部流量

当拥有一个门户主页的时候,同时想对用户离开主页后的流量进行跟踪,这时可以使用重定向。以yahoo.com为例,主页新闻的链接主机名是http://hsrd.yahoo.com/,后面跟着识别的参数,点击后再产生一个301重定向,这样就记录了离开门户主页后的流量去向。  

我们知道重定向是如何损伤性能的,为了实现更好的效率,可以使用Referer日志来跟踪内部流量去向。每个HTTP请求都有一个Referer表示原始请求页(除了从书签打开或直接键入URL等操作),记录下每个请求的Referer,就避免了向用户发送重定向,从而改善了响应时间。

2. 跟踪出站流量

有时链接可能将用户带离你的网站,在这种情况下,使用Referer就不太现实了。

同样也可以使用重定向来解决跟踪出站流量问题。以百度搜索为例,百度通过将每个链接包装到一个302重定向来解决跟踪的问题,例如搜索关键字“跟踪出站流量”,搜索结果的第一个URL为http://www.baidu.com/link?url=后面跟着一连串字符,即使搜索结果并没有变,但这个字符串是动态改变的,我认为这里的搜索连接URL好像没有改变的需要,不知道这里起到怎样的作用?

除了重定向外,我们还可以选择使用信标(beacon)——一个HTTP请求,其URL中包含有跟踪信息。跟踪信息可以从信标Web服务器的访问日记中提取出来,信标通常是一个1px*1px的透明图片,不过204响应更优秀,因为它更小,从来不被缓存,而且绝不会改变浏览器的状态。

四、减少Cookie传输
 一方面,Cookie包含在每次请求和响应中,太大的Cookie会严重影响数据传输,因此哪些数据需要写入Cookie需要慎重考虑,尽量减少Cookie中传输的数据量。另一方面对于某些静态资源的访问,如CSS、Script等,发送Cookie没有意义,可以考虑静态资源使用独立域名访问,避免请求静态资源时发送Cookie,减少Cookie传输的次数。
  因为Cookie是本地的磁盘文件,每次浏览器都会去读取相应的Cookie,所以建议去除不必要的Coockie,使Coockie体积尽量小以减少对用户响应的影响;
  使用Cookie跨域操作时注意在适应级别的域名上设置coockie以便使子域名不受其影响。
  Cookie是有生命周期的,所以请注意设置合理的过期时间,合理地Expire时间和不要过早去清除coockie,都会改善用户的响应时间。

五、服务端启用压缩

  在服务器端对文件进行压缩,在浏览器对文件解压缩,可有效减少通信传输的数据量。文本文件的压缩率可达80%以上,因此HTML、CSS、JavaScript文件启用GZip压缩可达到较好的效果。但是压缩对服务器和浏览器产生一定的压力,在通信带宽良好,而服务器资源不足的情况下要权衡考虑。

 

六、CSS放在页面最上面、JavaScript放在页面最下面

        浏览器会在下载完全部CSS之后才对整个页面进行渲染,因此最好的做法是将CSS放在页面最上面,让浏览器尽快下载CSS,HTML规范清楚指出CSS要放包含在页面的区域内。JavaScript则相反,浏览器在加载JavaScript后立即执行,有可能会阻塞整个页面,造成页面显示缓慢,因此JavaScript最好放在页面最下面,但如果页面解析时就需要用到JavaScript,这里放在底部就不合适了。
  浏览器在执行JavaScript代码时,不能同时做其它事情,即<script>标签每次出现都会让页面等待脚本的解析和执行(不论JavaScript是内嵌的还是外链的),JavaScript代码执行完成后,才继续渲染页面。这个也就是JavaScript的阻塞特性。因为这个阻塞的特点,建议把JavaScript代码放到</body>标签以前,这样既能有效的防止JavaScript的阻塞,又能使得页面的HTML结构能更快的释放。

七、压缩HTML、js、css、img

压缩是指从去除代码不必要的字符减少文件大小从而节省下载时间。 
方法: 
1.去除不必要的空白符(空格、换行、tab缩进)、格式符、注释符 
2.简写方法名、参数名来压缩js脚本 
在 JavaScript中,由于需要下载的文件体积变小了从而节省了响应时间。

八、使用外部文件JavaScriptCSS,移除重复的脚本及代码



单独提取好处: 
(1)提高了js和css的复用性 
(2)减小页面体积 
(3)提高了js和css的可维护性 


内联的好处: 
(1)减少页面请求 
(2)提升页面渲染速度 

 


使用内联的情况: 
(1)脚本和样式只应用于一个页面 
(2)页面不经常被访问 
(3)脚本和样式很少的情况 

 


在实际应用中使用外部文件可以提高页面速度,因为JavaScript和CSS文件都能在浏览器中产生缓存。内置在HTML文档中的JavaScript 和CSS则会在每次请求中随HTML文档重新下载。这虽然减少了HTTP请求的次数,却增加了HTML文档的大小。从另一方面来说,如果外部文件中的 JavaScript和CSS被浏览器缓存,在没有增加HTTP请求次数的同时可以减少HTML文档的大小。

 

重复脚本会引起不必要的HTTP请求和无用的JavaScript运算,这降低了网站性能。

九、减少对DOM的操作

 Repaint 和 Reflow 也就是重绘和重排(回流)。

当渲染树中的一部分或者全部因为元素的尺寸、布局、隐藏等改变而需要重新构建的时候,这时候就会发生回流。

在回流的时候,浏览器会使渲染树中受到影响的元素部分失效,并重新绘制这个部分的渲染树,完成回流以后,浏览器会重新绘制受到影响的部分元素到屏幕中,这个过程就是重绘。

每次对dom的操作都会触发"重排",这严重影响到能耗,一般通常采取的做法是尽可能的减少dom操作来减少"重排"。

设置style属性改变节点点样式的话,每设置一次都会导致一次reflow,所以最好通过设置class的方式;有动画效果的元素,它的position属性应当设为fixedabsolute,这样不会影响其它元素的布局;如果功能需求上不能设置positionfixedabsolute,那么就权衡速度的平滑性。

 


  DOM操作应该是脚本中最耗性能的一类操作,例如增加、修改、删除 DOM元素或者对 DOM集合进行操作。如果脚本中包含了大量的 DOM操作则需要注意以下几点:
  a. HTML Collection(HTML收集器,返回的是一个数组内容信息)
  在脚本中 document.images、document.forms 、getElementsByTagName()返回的都是 HTMLCollection类型的集合,在平时使用的时候大多将它作为数组来使用,因为它有 length属性,也可以使用索引访问每一个元素。不过在访问性能上则比数组要差很多,原因是这个集合并不是一个静态的结果,它表示的仅仅是一个特定的查询,每次访问该集合时都会重新执行这个查询从而更新查询结果。所谓的 “访问集合” 包括读取集合的 length属性、访问集合中的元素。
  因此,当你需要遍历 HTML Collection的时候,尽量将它转为数组后再访问,以提高性能。即使不转换为数组,也请尽可能少的访问它,例如在遍历的时候可以将 length属性、成员保存到局部变量后再使用局部变量。


  (2). 慎用 with
with(obj){ p = 1}; 代码块的行为实际上是修改了代码块中的 执行环境 ,将obj放在了其作用域链的最前端,在 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方法得到结果。不过由于使用数组也有一定的开销,因此当需要拼接的字符串较多的时候可以考虑用此方法。

  
 
 

十、使用CDN加速
CDN的全称是Content Delivery Network,即内容分发网络。其目的是通过在现有的Internet中增加一层新的网络架构,将网站的内容发布到最接近用户的网络“边缘”,使用户可以就近取得所需的内容,提高用户访问网站的响应速度

CDN加速原理/CDN加速 编辑

CDN加速将网站的内容缓存在网络边缘(离用户接入网络最近的地方),然后在用户访问网站内容的时候,通过调度系统将用户的请求路由或者引导到离用户接入网络最近或者访问效果最佳的缓存服务器上,有该缓存服务器为用户提供内容服务;相对于直接访问源站,这种方式缩短了用户和内容之间的网络距离,从而达到加速的效果。

CDN的不足之处,实时性不好。不过,随着对CDN需求的逐渐升温,这一不足得到了改进,使来自于远程服务器的网络内容网页与复本服务器或缓存器中的网页保持同步。解决方法是在网络内容发生变化时将新的网络内容从服务器端直接传送到缓存器,或者当对网络内容的访问增加时将数据源服务器的网络内容尽可能实时地复制到缓存服务器

 

 

十一、使用JSON格式来进行数据交换

JSON是一种轻量级的数据交换格式,采用完全独立于语言的文本格式,是理想的数据交换格式。同时,JSON是 JavaScript原生格式,这意味着在 JavaScript 中处理 JSON数据不需要任何特殊的 API 或工具包。

与XML序列化相比,JSON序列化后产生的数据一般要比XML序列化后数据体积小,所以在Facebook等知名网站中都采用了JSON作为数据交换方式。

十二、反向代理

传统代理服务器:在浏览器一侧,代替浏览器发送HTTP请求;

反向代理服务器:在网站服务器一侧,代替网站服务器接收HTTP请求;

反向代理服务器可以通过配置缓存功能加速web请求,当用户第一次访问静态内容的时候,静态内容就被缓存在反向代理服务器上,这时候,如果有其他用户访问这个资源,反向代理服务器可以直接返回内容给用户。这样也可以达到加速响应速度和减轻web服务器压力的效果。

 

十三、使 AJAX 缓存

Post传递:每次都被执行,不会被缓存

Get传递:同一地址不重复执行,可以被缓存。

Ajax经常被提及的一个好处就是由于其从后台服务器传输信息的异步性而为用户带来的反馈的即时性。但是,使用Ajax并不能保证用户不会在等待异步的 JavaScript和XML响应上花费时间。在很多应用中,用户是否需要等待响应取决于Ajax如何来使用。记住一点,异步并不等同着即时,这很重要。 
为了提高性能,优化Ajax响应是很重要的。提高Ajax性能的措施中最重要的方法就是使响应具有可缓存性(为文件头指定ExpiresCache-Control )。一下几条的几条也同样适用于Ajax:

  • 压缩文件
  • 减少DNS查找次数
  • 精简JavaScript
  • 避免跳转
  • 配置ETag(实体标签)

 

十四、配置实体标签(ETag

 

Entity tag(ETag)(实体标签)是web服务器和浏览器用于判断浏览器缓存中的内容和服务器中的原始内容是否匹配的一种机制。如果一致,则直接使用缓存中的内容,不需要服务器提供了。 
增加ETag为实体的验证提供了一个比使用”last-modified date(上次编辑时间)”更加灵活的机制。Etag是一个识别内容版本号的唯一字符串。唯一的格式限制就是它必须包含在双引号内。原始服务器通过含有 ETag文件头的响应指定页面内容的ETag。

稍后,如果浏览器要验证一个文件,它会使用If-None-Match文件头来把ETag传回给原始服务器,如果ETag是匹配的,直接返回响应304(未修改——Not Modified)和一个空的响应体。

 

原文地址:https://www.cnblogs.com/zhyez/p/9052191.html