前端优化

64次阅读

共计 3184 个字符,预计需要花费 8 分钟才能阅读完成。

链接:前端优化

前端优化

浏览器发送 HTTP 请求,服务器收到请求全文后,返回 HTTP 响应,在浏览器接收之后结束这个过程。浏览器和服务器只有一次互动的机会,浏览器主动发起,而服务器被动地根据收到的请求内容返回结果。一个完整的请求都需要经过 DNS 寻址、与服务器建立连接、发送数据、等待服务器响应、接收数据的过程。

前端优化的途径

  1. 页面级别 的优化,例如 HTTP 请求数、脚本的无阻塞加载、内联脚本的位置优化等;
  2. 代码级别 的优化,例如 JavaScript 中的 DOM 操作优化、CSS 选择符优化、图片优化以及 HTML 结构优化等。

页面级优化

1. 减少 HTTP 请求数

减少 HTTP 请求数的主要途径

1、从设计实现层面简化页面

保持页面简洁、减少资源的使用 是最直接的。能使用 CSS 替代效果就尽量少使用图片。

2、合理设置 HTTP 缓存

恰当地缓存设置可以大大减少 HTTP 请求。被缓存资源的请求服务器是 304 响应,只有 Header 没有body,没有节省带宽。对于多个页面都可能使用到的代码,尽量拆分到同一个文件中。如果是嵌入页面换来的是增大了页面的体积,而且无法利用浏览器缓存。

3、资源合并和压缩

如果可以,尽可能将外部的脚本、样式进行合并,多个合为一个。另外,CSS、JavaScript、image 都可以用相应的工具进行压缩。

4、CSS Sprites

合并 CSS 图片,减少请求数的有一个好办法。

5、lazy load image

这个策略实际上并不一定能减少 HTTP 请求数,但是却能在某些条件下或者页面刚加载时减少 HTTP 请求数。对于图片而言,在页面刚加载时可以只加载第一屏,当用户继续往后滚屏时才加载后续的图片。以前的做法是在加载时把第一屏之后的图片地址缓存在 textarea 标签中,待用户往下滚屏时才 惰性 加载。百度图片和花瓣网也是用这种流行的瀑布流加载图片。

2. 将外部脚本置底

外链脚本在加载时会阻塞其他资源 ,例如在脚本加载完成之前,它后面的图片、样式以及其他脚本都处于阻塞状态,直到脚本加载完成后才会开始加载。如果把脚本放在比较靠前的位置,则会影响整个页面的加载速度从而影响用户体验。最简单可依赖的方法是将脚本尽可能往后挪,减少对并发下载的影响。如果时效性允许的话,可以考虑在DOMLoaded 事件触发时加载,或者用 setTimeout 方式来灵活控制加载的时机。

3. 异步执行 inline 脚本

inline脚本对性能的影响比外部脚本大很多。首先,与外部脚本一样,inline脚本在执行时也会阻塞并发请求,除此之外,由于浏览器在页面处理方面时单线程的,当 inline 脚本在页面渲染之前执行时,页面的渲染工作则会被推迟。简而言之,inline脚本在执行时页面处于空白状态。

鉴于以上两点,建议将 执行时间较长的 inline 脚本异步执行 。异步执行的方式有很多种,例如使用script 元素的 defer 属性、使用 setTimeout,此外,在 HTML5 中引入了web workers 的机制,恰恰可以解决此类问题。

4. lazy load JavaScript

目前的做法大概有两种,一种是为流量特别大的页面专门定制一个专用的 mini 版框架,另一种则是 lazy load,最初只加载核心模块,其他模块可以等到需要使用的时候才加载,类似于javaswing,引入需要的组件库文件。

5. 将 CSS 放在 head

6. 减少不必要的 HTTP 跳转

对于以目录形式访问的 HTTP 链接,很多人都会忽略链接最后是否带/,假如服务器对此区别对待,那么其中很可能隐藏了 301 跳转,增加了多余请求。

代码级优化

1. JavaScript

1、DOM

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

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

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

2、慎用with

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

因此,除非你能 肯定在 with 代码中脂肪纹 obj 中的属性,否则慎用with,替代的可以使用局部变量缓存需要访问的属性。

3、避免使用 evalFunction

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

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

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

此外,使用 evalFunction不利于 JavaScript 压缩工具执行压缩。

4、减少作用域链查找

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

此外,要减少作用域链查找还应该减少闭包的使用。闭包的变量可能保存到内存中,内存消耗很大,解决方法是在退出函数前,将不使用的局部变量删除。

5、数据访问

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

  1. 对任何 对象属性 的访问超过 1 次
  2. 对任何 数组成员 的访问次数超过 1 次

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

6、字符串拼接

在 JavaScript 中使用 + 号来拼接字符串效率是比较低的,因为每次运行都会开辟新的内存并生成新的字符串变量,然后拼接结果赋值给新变量。之前使用 jQuery+Ajax 交互页面,很多时候都是将后台传输过来的数据和前端 HTML 结构拼接成字符串,然后呈现在页面 HTML 容器里。

与之相比更为高效的做法是 使用数组的 join 方法 ,即将需要拼接的字符串放在数组中最后调用其join 方法得到结果。不过由于使用数组也有一定的开销,因此当需要拼接的字符串较多时可以考虑使用此方法。

2. CSS 选择符

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

如果是从右往左解析则效率会很高,因为第一个 ID 选择基本上就把查找的范围限定了,但实际上浏览器对选择符的解析是从右往左进行的。#tag A {color: "#ccc";},浏览器必须遍历查找每一个 A 标签的祖先节点,效率并不像之前想象的那么高。根据浏览器的这一行为特点,在写选择符的时候需要注意很多事项。

正文完
 0