js性能的進階
阿新 • • 發佈:2018-10-31
func UNC 性能提高 adding con png console rip ()
為了說明js性能方面的差異用一個簡單的例子說明下,
<style> #ul1{ padding: 5px; overflow: hidden; } #ul1 li{ list-style: none; width: 15px; height: 15px; border-radius: 50%; background: #ccc; margin: 3px; float: left; cursor: pointer; } #ul1 .active{ background: red; } </style> <ul id="ul1"> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> <li></li> ... </ul>
這樣一個很簡單的列表。做成一個單選效果,給被點擊的li添加一個active的class。
實現的發方法有很多種,我介紹4中,為了能清楚看到性能之間的差異,li元素我復制了2000個。
第一種方法,也是最不可取,性能也是最浪費的一種
console.time("time1"); $("#ul1 li").click(function(event) { console.time("time2"); $("#ul1 li").removeClass(‘active‘); $(this).addClass(‘active‘); console.timeEnd("time2"); }); console.timeEnd("time1");
這方法可能是初學者最易用到的,他的性能如下
首次事件綁定用了11ms ,之後每次點擊0.6ms左右,前幾次用的時間比較多。
第二種方案
console.time("time1"); var arrli = $("#ul1 li"); arrli.click(function(event) { console.time("time2"); arrli.removeClass(‘active‘); $(this).addClass(‘active‘); console.timeEnd("time2"); }); console.timeEnd("time1");
相對第一種情況首次花費時間多了,每次點擊花費時間少了,這次把jquery dom做了緩存沒有每次都進行dom選擇
第三種方案,這種代碼量比較多,采用了dom緩存,和虛擬dom的概念。避免沒有必要的直接操作dom
同時為了提高性避開使用query的選擇器
console.time("time1"); var arrli = []; var lilist = document.querySelectorAll("#ul1 li"); for(var i=0,len=lilist.length;i<len;i++){ var jsn = {}; jsn._active = false;//代表該元素的選中狀態[虛擬dom的概念] jsn.dom = $(lilist[i]);//把源生對象轉為query對象 arrli.push(jsn); lilist[i].setAttribute("index",i);//添加一個數組中索引的屬性 lilist[i].onclick = function(){ console.time("time2"); var index = this.getAttribute("index")*1; for(var i=0,len=arrli.length;i<len;i++){ if(i === index){ //只有在沒有選中的時候進行選中設置 if(!arrli[i]._active){ arrli[i]._active = true; arrli[i].dom.addClass(‘active‘); }; }else{ if(arrli[i]._active){ arrli[i]._active = false; arrli[i].dom.removeClass(‘active‘); }; }; }; console.timeEnd("time2"); }; }; console.timeEnd("time1");
看性能
首次耗時4.6ms,使用原生的選擇器快了很多。每次點擊最多的一次耗時也是0.1ms,所以相對前兩種方案性能提高了很多。
第四種方案
基於第三種方案,每次點擊的時候會循環下,這種方案避開這種循環
console.time("time1"); var arrli = []; var lilist = document.querySelectorAll("#ul1 li"); var old = false; for(var i=0,len=lilist.length;i<len;i++){ var jsn = {}; jsn._active = false;//代表該元素的選中狀態[虛擬dom的概念] jsn.dom = $(lilist[i]);//把源生對象轉為query對象 arrli.push(jsn); lilist[i].setAttribute("index",i);//添加一個數組中索引的屬性 lilist[i].onclick = function(){ console.time("time2"); var index = this.getAttribute("index")*1; //這個方案不需要循環 if(old){ old._active = false; old.dom.removeClass(‘active‘); }; if(!arrli[index]._active){ arrli[index]._active = true; arrli[index].dom.addClass(‘active‘); old = arrli[index]; }; console.timeEnd("time2"); }; }; console.timeEnd("time1");
性能
相對第三種代碼改變並不多,性能方面每次點擊所花費的時間有所提高,缺點是後兩種增加了代碼量
js性能的進階