浅谈 Javascript 性能优化

浅谈 Javascript 性能优化 - Presentation Transcript 浅谈 JavaScript 性能优化 龙刚 (@RainoXu)TaobaoUED www.rainoxu.com 优化 JavaScript性能,使它运行足够快一个关键因素:运行的时间 响应时间与用户的体验 0.1s 用户觉得很流畅 1.0s 用户的操作可能偶尔受到影响,并且用户已经能感觉到有些不流畅 10s 对用户的影响比较严重,需要相应的进度提示。用户也会有一些沮丧 What To Do && How To Do? 管理作用域 操作数据 流控制 Reflow DOM操作 长时间运行的脚本处理 管理作用域 function add(num1, num2){ return num1 + num2; } var result = add(5, 10); 使用局部变量 局部变量存在于活动对象中,解析器只需查找作用域中的单个对象 var a = 1; function test(){ //对变量a进行一系列操作 } function test2(){ var a = 1; //对变量a进行一系列操作 } 另一个例子 (function(win, S, undefined) { ... ... var doc = win['document'], loc = location, EMPTY = '', ... ... })(window, 'KISSY'); 数据操作 使用局部变量,它是最快的缓存频繁使用的对象、数组及相关的属性值 obj.name比obj.xxx.name访问更快,访问属性的速度,与其在对象中的深度有关 “ . ”操作的次数直接影响着访问对象属性的耗时 varobjName = obj.name; KISSY.add('switchable', function(S, undefined) { var DOM = S.DOM, Event = S.Event, ... ... }); function process(data){ if (data. count> 0){ for(vari = 0; i < data.count; i++){ processData(data.item[i]); } } } function process(data){ var count = data.count; if (count > 0){ for(vari = 0; i < count ; i++){ processData(data.item[i]); } } } NodeList 不直接操作NodeList,将其转换成静态数组后再使用 方法: Array.prototype.slice.call() => 标准浏览器 逐个拷贝到一个新数组中 => For IE 大部分JS库都有提供将Array-Like的对象转变成Array的方法(如KISSY提供的makeArray()方法);部分JS库在返回元素集合时,已预处理成Array(例子:YUI的DOM相关操作方法) 遍历NodeList时,不做对当前NodeList相关结构有影响的DOM操作,并且如之前所提到的,要缓存一些频繁使用到的属性值,以避免杯具发生。 vardivs = document.getElementsByTagName('DIV'); //假定页面中有div,所以divs.length是大于0的 for (varidx = 0; idx < divs.length; idx++){ document.body.appendChild( //杯具悄然而置 document.createElement('DIV') ); console.info(divs.length); } 杯具的原因? 通过getElementsByTagName()获取得到的是一个LiveNodeList的引用,任何对其相关的DOM操作都会立即反应在这个NodeList上面 通过不断地往document.body下插入div 节点,for循环的终止条件(div.length也随之改变)失效,陷入死循环。 Live NodeListvs Static NodeList 理论上,静态的东西应该是最快的,但是实际情况是,Live NodeList更快。 Live NodeListvs Static NodeList 原因:目前市场上的浏览器,对Live NodeList做了缓存 Live NodeListvs Static NodeList 结论:优先使用Live NodeList,通过选择器获取以后,再进一步转换成数组来使用。这也是目前许多JS库在使用的方案。 DOM操作 指明操作DOM的context YUI: Array getElementsByClassName ( className , tag , root , apply , o , overrides ) KISSY: Array query ( selector, context ) 即便是用原生的JS,也应该指明: context.getElementsByTagName() DOM操作 增删、修改节点 使用DocumentFragment 使用cloneNode()复制一份目标节点来处理 如果是直接修改DOM,请先将其display:none; 一个方法尽可能只做一件事 拆分功能,让一个方法只做一件事,通过不断地调用方法来实现复杂功能,但是,这些简单方法要避免相互交叉调用。 KISSY Poster中的一些方法拆分 KISSY Poster中的一些方法拆分 Be Lazy 使脚本尽可能少地运行,或者不运行。 短路表达式应用:如 a && b || c 基于事件去写相应的处理方法 惰性函数 合理地使用事件代理 DOM与事件处理 为元素绑定事件 Event.on ( target, type, fn, scope ) 事件代理的原理 冒泡 捕获 事件代理应用的场景? Event.on(container, ‘click’, function (ev){ var target = ev.target(); switch(target.className){//或者可以是nodeName ... ... ... } }); 流控制 if(...){ }elseif(...){ }elseif(...){ }elseif(...){ }elseif(...){ }elseif(...){ }else{ } 在if语句中,将经常会发生的条件,放在靠上的位置 if的条件为连续的区间时,可以使用二分法的方式来拆分 较多离散值的判断,可以使用switch来替代 使用数组查询的方式 要注意隐式的类型转换 varfoo = 0; if(foo == false){ ... } 小心递归! function recurse(){ recurse(); } recurse();//又是一个杯具 浏览器对调用栈的最大限度的定义各不一样 递归的相互调用、自身调用可能触发浏览器的调用栈的最大极限 Reflow 主要引起Reflow的因素 操作DOM树 与布局有关的样式改变 改变className 窗口大小调整 字休大小 优化运行时间较长的脚本 原因: 大量DOM操作 过多的循环与递归 解决问题的最佳实践: 使用定时器 最后,优化原则? 2/8原则 考虑大多数情况,极端情况,有能力则兼顾之,适当取舍 性能与可维护性权衡之一原则 站在巨人的肩膀上,看得更远 YAHOO的前端小组、JohnResig、NicholasC.Zakas等都已经总结了很多有用的性能优化方面的经验,以他们的研究成果做为优化时的参考。 好的编程习惯 不以善小而不为 思先于行,不必过早优化 最后,感谢玉伯、云谦、圆心、龙俊、释然对我此次的分享提供了许多帮助和建议。 Question?
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值