我们建立网站就是想让目标人群来访问,前端是用户所直接接触的。为了给用户更好的体验,前端性能优化是必须滴!最近读了本《高性能的JavaScript》,然后结合实际遇到的问题。总结以下几个方面进行前端性能优化:
一、 加载
<body>标签闭合之前,将js放在底部,将css放在顶部
这样能保证在脚本执行之前页面已经完成渲染,避免加载js对后续的资源造成阻塞。
二、 数据
1. 能使用局部变量。和字面量(int a=1)的,尽量不使用全局变量
因为局部变量存在作用域链的 起始位置 ,因此访问局部变量比访问跨作用域链的变量更快。变量在作用域链的位置越深,访问时间越长,而全局变量处在作用域链的 最末端 ,因此访问速度最慢。
2. 嵌套对象成员会影响性能,尽量少用
嵌套越深,读取越慢,每次的点操作符,js引擎都会搜索所有的对象成员。所以location.href优于window.location.href
3.缓存对象成员值
把常用的对象成员,数组元素,跨域变量保存在局部变量中,前面也说了局部变量的访问速度是最快的捏!
三、 DOM编程
1. 最小化DOM访问次数
因为DOM访问次数越多,DOM重绘重排就越多,如果要多次改动DOM结构,就应该把要改动的部分先取出来,改动完成后再放回去。
2.使用局部变量存储DOM节点的引用
如果需要多次访问某个DOM节点,使用局部变量存储它的引用
3.把集合的长度缓存到变量中,并在迭代中使用它
4.使用事件委托减少事件处理器的数量
那什么是事件委托,可参考我的其中一篇博文,js事件委托
四、 算法和控制流程
1. 避免使用 for-in 循环
数组一定不要 用 for-in 循环,除非遍历个属性数量未知的对象
2. 避免使用多重循环
改善性能最佳方式就是减少每次迭代的运算量和减少循环迭代的次数
3. 正确使用 switch和if-else
通常来说,switch是比if-else更快,但是在条件数量很大时才明显,所以通常,条件数量少的时候使用 if-else
五、 实践中
1. 尽量使用直接量创建对象和数组
直接量的创建和初始化都比非直接量形式要快
2. 考虑使用位运算 进行数学计算
但是位运算感觉容易出错,而且比较复杂,所以我基本不用,嘿嘿。。。
3. 尽量使用javascript的原生方法
六、 构建和部署(最重要的方面)
1. 减少http请求次数
网站提速最重要的一条规则就是减如少页面渲染所需的http请求数。每次http请求都需要建立通信链路、进行数据传输,而在服务器端,每个http都需要启动独立的线程去处理。
2. 合并压缩
减少http请求次数,合并多个图片,js和css文件。比如加载一个页面,果有5个css文件的话,那么会发出5次http请求,这样会让用户第一次访问你的页面的时候会长时间等待。而如果把这个5个文件合成一个的话,就只需要发出一次http请求,节省网络请求时间,加快页面的加载。合并css图片,使用Sprites。Javascript压缩,可以把文件中与运行无关的部分进行剥离,比如包括注释和不必要的空白字符。这样的过程通常可以将文件大小减半,使文件更快的被下载,缩小请求返回的数据量。
3. 使用构建工具,比如gulp
在构建时能完成的工作就不要留到 运行中,像合并,压缩,预处理这些步骤最好都是在构建时先完成。
4. 避免空的src和href
当link标签的href属性为空、script标签的src属性为空的时候,浏览器渲染的时候会把当前页面的URL作为它们的属性值,从而把页面的内容加载进来作为它们的值。所以要避免犯这样的疏忽。
5. 避免使用CSS表达式和内联的CSS样式
将CSS和JS放到外部文件中,目的是缓存文件。 但有时候为了减少请求,也会直接写到页面里,这个需根据PV和IP的比例权衡。
6. 图片使用延时加载
我现在的做法是,将图片的src用占位符图片代替,并使用data-src属性保存真实的图片地址,然后监控window的scroll事件,当图片出现在屏幕中时,就将data-src的值赋值给src。
7. 设置缓存
当用户在浏览器的地址栏中敲入了网站的网址 ( 比如 google.com ) ,浏览器首先会通过访问的域名来定位到IP (DNS) 从而找到去哪里获取资源, 这时, 浏览器会依次进行如下查找:
- 浏览器缓存
- 系统缓存
- 路由器缓存
- ISP DNS缓存
- 递归搜索…
所以对一个网站而言,设置缓存是必要的。特别是像CSS、javascript、logo、图标这些静态资源文件更新的频率都比较低,而这些文件又几乎是每次http请求都需要的,如果将这些文件缓存在浏览器中,它可以极好的改善性能。
设置缓存的原创很简单,能缓存越多越好,能缓存越久越好。通过设置http头中的cache-control和expires的属性,可设定浏览器缓存,缓存时间可以是数天,甚至是几个月。
例如,很少变化的图片资源可以直接通过 HTTP Header中的Expires设置一个很长的过期头 ;变化不频繁而又可能会变的资源可以使用Last-Modifed来做请求验证。尽可能的让资源能够在缓存中待得更久。 - 为文件头指定
ExpiresExipres是用来设置文件的过期时间的,一般对css、js、图片资源有效。 他可以使内容具有缓存性,这样下回再访问同样的资源时就通过浏览器缓存区读取,不需要再发出http请求。 - 配置ETags
响应头部中会包含一个ETag的信息,它用来判断浏览器缓存里的元素是否和原来服务器上的一致。比last-modified更具有弹性,例如某个文件在1秒内修改了10次,Etag可以综合Inode(文件的索引节点(inode)数),MTime(修改时间)和Size来精准的进行判断,避开UNIX记录MTime只能精确到秒的问题。 服务器集群使用,可取后两个参数。使用ETags减少Web应用带宽和负载。
浏览器请求具体过程可看下图:
值得注意的是: 适当的缓存可以提升用户体验,但是有个缺点,当应用升级时,我们要把用户缓存的静态资源更新。这个可以通过静态资源重命名解决,一般我们是给文件增加一个版本号或者开发编号。还有就是不宜一次更新全部文件,应该一个个逐步更新,忽然大量缓存失效,会使服务器负载骤增,网络堵塞的
8. 权衡DNS查找次数
我们来分析一下浏览器与服务器之间一次典型的通信过程.
- DNS 查询
- TCP 连接
- HTTP 请求与响应
所以减少主机名会节省响应时间,但是同时也会减少并行的下载数量,IE浏览器同一时刻只能从同一域名下载两个文件,所以会影响下载速度。所以我们可以用多个域名来存放图片,例如可以看下新浪微博的图片存放。你会发现有的图片的地址是 http://tva2.sinaimg.cn/, 有的图片则是 http://ww2.sinaimg.cn/
9. 使用内容分发网络(CDN)
CDN(contentdistribute network,内容分发网络)的本质仍然是一个缓存,而且 将数据缓存在离用户最近的地方 ,使用户以最快速度获取数据。CDN缓存的一般是静态资源,如图片、文件、CSS、script脚本、静态网页等,但是这些文件访问频度很高,将其缓存在CDN可极大改善网页的打开速度。
10. 使用GET来完成AJAX请求
当使用XMLHttpRequest时,浏览器中的POST方法是一个“两步走”的过程:首先发送文件头,然后才发送数据。因此使用GET获取数据时更加有意义。当数据量小的时候使用 GET ,超过2048个字节的时候用POST。因为ie限制URL长度,过长会导致URL被截断
11. 避免使用 eval和 Function 构造函数
会导致双重求值得性能消耗