Web前端性能优化常见面试题

一般说来,web前端指网站业务逻辑之前的部分,包括浏览器加载、网站视图模型、图片服务、CDN服务等,主要优化手段有浏览器访问、使用反向代理才、CDN等。
1、减少http请求,合理浏览器缓存

2、启用压缩:HTML、CSS、javascript文件启用GZip压缩可达到较好的效果

3、CSS Sprites:合并 CSS图片,减少请求数的又一个好办法。
4、LazyLoad Images:在页面刚加载的时候可以只加载第一屏,当用户继续往后滚屏的时候才加载后续的图片
5、CSS放在页面最上部,javascript放在页面最下面:让浏览器尽快下载CSS渲染页面
6、异步请求Callback(就是将一些行为样式提取出来,慢慢的加载信息的内容)
在某些页面中可能存在这样一种需求,需要使用 script标签来异步的请求数据。类似:
<span style="font-size:14px;">/*Callback 函数*/
function myCallback(info){ 
//do something here 

 HTML:
  Callback返回的内容 :
myCallback('Hello world!');
</span>
像以上这种方式直接在页面上写 <script> 对页面的性能也是有影响的,即增加了页面首次加载的负担,推迟了 DOMLoaded和window.onload 事件的触发时机。如果时效性允许的话,可以考虑在 DOMLoaded事件触发的时候加载,或者使用 setTimeout方式来灵活的控制加载的时机。

7、减少cookie传输
一方面,cookie包含在每次请求和响应中,太大的cookie会严重影响数据传输,因此哪些数据需要写入cookie需要慎重考虑,尽量减少cookie中传输的数据量。另一方面,对于某些静态资源的访问,如CSS、script等,发送cookie没有意义,可以考虑静态资源使用独立域名访问,避免请求静态资源时发送cookie,减少cookie传输次数。

8、Javascript代码优化

(1). DOM  

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

(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). 减少作用域链查找

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

<span style="font-size:14px;">// 全局变量 
var globalVar = 1; 
function myCallback(info){ 
for( var i = 100000; i--;){ 
//每次访问 globalVar 都需要查找到作用域链最顶端,本例中需要访问 100000 次 
globalVar += i; 
}

</span>

更高效的写法:

<span style="font-size:14px;">// 全局变量 
var globalVar = 1; 
function myCallback(info){ 
//局部变量缓存全局变量 
var localVar = globalVar; 
for( var i = 100000; i--;){ 
//访问局部变量是最快的 
localVar += i; 

//本例中只需要访问 2次全局变量
在函数中只需要将 globalVar中内容的值赋给localVar 中
globalVar = localVar; 
}
</span>

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

(5). 数据访问

  Javascript中的数据访问包括直接量 (字符串、正则表达式 )、变量、对象属性以及数组,其中对直接量和局部变量的访问是最快的,对对象属性以及数组的访问需要更大的开销。当出现以下情况时,建议将数据放入局部变量: 
  a. 对任何对象属性的访问超过 1次 
  b. 对任何数组成员的访问次数超过 1次 
  另外,还应当尽可能的减少对对象以及数组深度查找。

(6). 字符串拼接

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

9、CSS选择符优化

在大多数人的观念中,都觉得浏览器对 CSS选择符的解析式从左往右进行的,例如 
#toc A { color: #444; }这样一个选择符,如果是从右往左解析则效率会很高,因为第一个 ID选择基本上就把查找的范围限定了,但实际上浏览器对选择符的解析是从右往左进行的。如上面的选择符,浏览器必须遍历查找每一个 A标签的祖先节点,效率并不像之前想象的那样高。根据浏览器的这一行为特点,在写选择符的时候需要注意很多事项,有兴趣的童鞋可以去了解一下。

CDN加速

CDN(contentdistribute network,内容分发网络)的本质仍然是一个缓存,而且将数据缓存在离用户最近的地方,使用户以最快速度获取数据,即所谓网络访问第一跳,如下图。

由于CDN部署在网络运营商的机房,这些运营商又是终端用户的网络服务提供商,因此用户请求路由的第一跳就到达了CDN服务器,当CDN中存在浏览器请求的资源时,从CDN直接返回给浏览器,最短路径返回响应,加快用户访问速度,减少数据中心负载压力。 
CDN缓存的一般是静态资源,如图片、文件、CSS、script脚本、静态网页等,但是这些文件访问频度很高,将其缓存在CDN可极大改善网页的打开速度。

反向代理

传统代理服务器位于浏览器一侧,代理浏览器将http请求发送到互联网上,而反向代理服务器位于网站机房一侧,代理网站web服务器接收http请求。

上一篇:position 定位


下一篇:maven+nexus setting.xml配置(收藏)