关于前端性能的一点整理(未完待续)

整理一些自己在平时看到过的有关性能优化的东西(未完待续)

前段时间看到很多人在提到有关算法的东西,后来想了想感觉步入前端这个行业,算法这个东西貌似相对于后端来说更为遥远了,个人觉得算法提供了两种思路:一种是解决问题的办法,还有一种是提高效率的途径。解决问题的办法诸如那些图的算法等等,提高效率的话有贪心,排序等等一些,这些对于后端确实应该挺重要的,或者是数据库的查询;不过对于前端,所关注的也许是其他的东西了,因为在其他上面所能提高的东西远远大于这些。[仅是个人的一点点见解,最后有一个关于《高性能网站建设指南》的阅读笔记,所以在那里出现的对象,我就不累赘了]

##HTML##

  1. 关于 \<\img src=”” >这样图片的资源链接为空的情况下,之前在几篇文章里看到会产生一个比较奇怪的现象就是会对页面发起两次请求,建议用个默认的图片先;(这里补充一点,就是当这个src属性为空的时候,js读这个属性,读到的不是””,而是此时的location.href)
  2. 关于图片一般在切图的时候都会有大小的限制,所以可以给他的外边框在写的时候都加上高度跟宽度,这样避免图片一开始没有到后面有,内容上发生一个抖动,而且对于浏览器来说,这样的重构渲染树也是比较损耗的

##css##

  1. css选择器的效率 !! div.nav > ul li a[title]
    上面的实例来说,浏览器首先会尝试在你的HTML标签中寻找“a[title]”元素,接着在匹配“li和ul”,最后在去匹配“div.nav”。这就是前成所主的“选择器从右到左的原则”,所以根据这样的原则,其实不可以在为了定义一个具体class的样式,通过很多层的套用

##javascript##

  1. 变量的缓存(分几种应用场景)
     (1) 作用域链和原型链上的优化:原型链的查找需要沿着原型链以此往上进行遍历,所以将需要的直接保存在一个变量中
     (2) 多层对象上的缓存,比如

    var _obj = {
        A :{
            A1 : {
                name : "ok"
            }
        }
    };
    

    要经常使用_obj.A.A1.name的话,最好也将他缓存起来,感觉有点类似空间来换时间的感觉,少查找几次
     (3) for循环数组缓存数组长度:一般的情况下数组的长度都是固定的所以每次都去读同一个数组的长度这里的损耗
     (4) 对一些变量的undefine判断可以试用void 0;之前看到一个解释是如下:void 0效果等同undefined,只是undefined是一个全局变量,需要变量名查找,void 0不但字数少,而且理论上避免了对undefined变量名的查找,效率高,理论上!!!(这点也是当时看underscore的时候发现的)
     (5)缓存DOM对象:这个还是很明显,每次查找一个id或者一个class,都是比较消耗的,id还好,因为在语义上就指明了是唯一出现的,我也没具体了解过这个查找方法具体是怎么实现的,不过感觉应该是只要找到一个id就可以停止搜索了,而对于class应该都是要遍历一遍文档的,所以做好这些对象的缓存估计可以提升不少的效果
     
     总结:其实还有一点关于这个缓存的解释就是一般的情况下,最后的代码都会需要进行压缩,所以如果一个变量是_obj.A.A1.name,那么进行压缩后最少也应该是a.b.c.d这样的形式,不过如果你进行了缓存,那么最后的情况会是a,这里可能会对压缩完毕的代码大小有一定的影响(来自于前几天看的一个jquery解释视频里提到的)

  2. 控制好一些经常触发的事件的频率:比如有时候需要的时候会对浏览的onresize事件进行监听,如果不控制好频率,只是一味的在当外界resize的时候就触发这个动作,那么对于浏览的监听事件也有点过于损耗了,想象一些,当你调整浏览器的时候,他是每一个时间的间隔其实都触发了这个事件,特别是当那个监听事件里写了很多复杂的而且消耗资源的事件,这样貌似在低版本的一些浏览器都会卡住,解决的方法就是

    var resizeEvent = null;
    if (resizeEvent) {
        clearTimeout(resizeEvent)
    }
    resizeEvent = setTimeout(function(){
        /*event*/
    }, 400);
    

3. 做好回收的工作:

  (1) 注意一些事件的回收,比如在用模块的方式来写代码的时候,一个模块调用进来注册了一些事件,然后当这个模块被切换走的时候,要注意把这些事件都进行清空处理,现在正常的js的垃圾回收应该都是引用计数的,所以长期这样切过来切过去,会有很多无效的浪费,更重要的是同一个模块被切回来切出去的动作经常进行的话,会在一个动作上触发同一个事件很多次,比如发一个请求发了很多次,这里也是有一些损耗的;
  (2) 注意那些闭包的回收;
  (3) 注意类似setTimeout这类的回收;

  1. 后续继续更新

##其他##


附上之前看过的《高性能网站建设》的一点笔记

###绪论###

  1. 黄金法则:只有10%~20%的最终用户相应时间花在了下载HTML文档上,其他都是花在了下载页面中的所有组件上
  2. 压缩:有时候发送一个请求,可以带上一个Accept-Encoding来表明支持压缩;
  3. 条件get请求:如果浏览器中保存了一个组建的副本,可以发送一个请求中附带着modified的信息,然后服务器可以对比下,如果缓存有效地话可以用一个更小且更快的响应返回给浏览器(304 not modify)
  4. Expires:虽然方法3可以让页面加载更快,但是还是需要客户端和服务器之间一次的来回;而Expires可以消除这个需求
  5. Keep-alive:在http的早期的实现中,http请求都是要打开一个socket的请求;有时候页面中的很多资源都是同时指向同一个服务器,持久链接就是解决了这个问题 [需要研究下持久连接的]

###规则1-减少http请求###

  1. 用图片中的map的方法,这样一块区域只需要一次图片的请求
  2. css Sprites 切图定位
  3. 内联图片(比如图片的信息可以试用base64的编码)
  4. 合并脚本和样式表

###规则2-使用内容发布网络Content Delivery Network (CDN)###
CND:一组分布在多个不同地理位置的web服务器,用于更加有效向用户发布内容;向特定用户发布内容的服务器的选择基于对网络可用度的测量(例如选择网络阶跳跃数最小的服务器,或者是具有最短响应时间的服务器)

CND:用于发布静态内容,如图片、脚本、样式表和Flash,不过有一个缺点是响应事件可能会受到其他网站的影响,CND服务提供商在其所有客户之间共享web服务器组件,还有一个缺点就是不能直接控制组件服务器带来的麻烦(比如修改http响应头)

###规则3-添加Expires头###

  1. Expires头
    web服务器试用这个表示来告诉客户端可以使用当前的副本直到某个时间
    缺点:使用了一个特定的时间要求服务器和客户端的时钟严格同步,而且过期时间需要经常检查
  2. Max-Age 和 mod_expires(另一种方式)
    缺点是不支持HTTP1.1
  3. 空缓存VS完整缓存

  4. 缓存的对象不仅仅只是图片还可以是脚本样式表还有flash组件

  5. 修订文件名
    对于一些还没过过期时间,但是服务器已经更新内容的情况,浏览器还是不会进行更新的,这个时候可以采用修订文件名,比如加一个版本号

###规则4-压缩组件###

客户端可以通过http请求中的Accept-Encoding标示对压缩的支持

  1. 压缩的内容
    值得压缩的应该是包括XML和JSON在内的任何文本响应,对于图片和PDF不应该压缩,压缩会给服务端加一些压力,可能会浪费CPU资源;而且客户端需要对这些压缩的资源进行解压
  2. 代理缓存
    之前介绍的都是在浏览器于服务器直接通信的情况下;有时候浏览器会通过代理向服务器发送请求,然后代理会缓存请求的资源,代理需要处理好,一些客户端请求不要压缩一些客户端需要压缩的情况 可以试用字段vary
  3. 边缘情况
    有些浏览器不支持压缩的格式需要进行处理

###规则5-将样式表放在顶部###

注意@import会产生一些问题(导致组建下载无序性;出现白屏,无样式内容的闪烁),所以最好试用link,

###规则6-将脚本放在末尾###

  1. http1.1中规范建议浏览器从每个主机名并行地下载两个资源,具体还是需要看浏览器的;不过不是越多的并行下载越好,过多的并行下载反而会降低性能
  2. 脚本阻塞下载[脚本是不能进行并行下载的,原因:脚本里可能有document.write之类的方法;脚本中很有可能需要按照一定的顺序进行即有依赖关系]

###规则7-避免css表达式###

###规则8-使用外部js和css###

  1. 纯粹而言,内联更快;但是JS和CSS是有机会可以被缓存起来的
  2. 需要考虑的基准:页面查看、空缓存VS完整缓存、组件重用
  3. 加载后下载:意思就是某个页面加载完毕之后再加载一些资源,而这些资源是为了缓存起来,给用户访问其他页面所需要的资源提前先缓存下
  4. 动态内联:意思就是根据一定的条件在服务端进行处理,对某些情况返回的页面是内联的页面,而有些情况下返回的是外连的页面

###规则9-减少DNS查找###

这里还是需要衡量一下,因为前面提到了如果用了不同的服务器,那么一些资源可以进行并行的下载
通过使用Keep-Alive和较少的域名来减少DNS的查找

###规则10-精简javascript###

  1. 混淆
    缺点:混淆过程可能引入错误;不好维护;不好测试
  2. 精简css比如类的合并,还有就是字符串进行缩写

###规则11-避免重定向###

  1. 一些重定向的类型:
    300 301 302 303 304 305 306 307
    其中301 302是用的最多的
  2. 其他细节
    (1)在URL的结尾必须处出现/但是没有出现
    (2)主机名缺少结尾/不会产生重定向
    (3)连接网站、跟踪内部流量、跟踪出战流量、美化URL

###规则12-移除重复的脚本###
会产生不必要的HTTP请求、执行js所浪费的时间

###规则13-配置Etag###

###规则14-使Ajax可缓存###

确保Ajax请求遵守性能指导,尤其应具有长久的Expires头部

by tankpt
2014.09.14