最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

一次失敗的jQuery優(yōu)化嘗試小結

 更新時間:2011年02月06日 16:12:44   作者:  
我經(jīng)常抱怨jQuery的DOM操作性能并不優(yōu)秀,并且經(jīng)常嘗試用一些方法去進行優(yōu)化,但是越是優(yōu)化,越是沮喪地發(fā)現(xiàn)jQuery其實已經(jīng)做得很好,從使用者的角度能夠進行的優(yōu)化實在有限
(這并不意味著jQuery的性能是優(yōu)秀的, 反之只能說它是一個相對封閉的庫,無法從外部介入進行優(yōu)化)。這篇文章就記錄一次失敗的優(yōu)化經(jīng)歷。
優(yōu)化思想
這一次優(yōu)化的思想來自于數(shù)據(jù)庫。在數(shù)據(jù)庫優(yōu)化的時候,我們常會說“將大量的操作放在一個事務中一起提交,能有效提高效率”。雖然對數(shù)據(jù)庫不了解的我并不知道其原因,但是“事務”的思想?yún)s為我指明了方向(雖然是錯的……)。
因此我嘗試將“事務”這一概念引入到jQuery中,通過“打開”和“提交”事務,從外部對jQuery進行一些優(yōu)化,其最重要的在于減少each函數(shù)的循環(huán)次數(shù)。
眾所周知,jQuery的DOM操作,以get all, set first為標準,其中用于設置DOM屬性/樣式的操作,幾乎都是對選擇出來的元素的一次遍歷,jQuery.access函數(shù)就是其中最核心的部分,其中用于循環(huán)的代碼如下:
復制代碼 代碼如下:

// Setting one attribute
if ( value !== undefined ) {
// Optionally, function values get executed if exec is true
exec = !pass && exec && jQuery.isFunction(value);
for ( var i = 0; i < length; i++ ) {
fn(
elems[i],
key,
exec ? value.call(elems[i], i, fn(elems[i], key)) : value,
pass
);
}
return elems;
}

比如jQuery.fn.css函數(shù)就是這樣的:
復制代碼 代碼如下:

jQuery.fn.css = function( name, value ) {
// Setting 'undefined' is a no-op
if ( arguments.length === 2 && value === undefined ) {
return this;
}
return jQuery.access( this, name, value, true, function( elem, name, value ) {
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
});
};

因此,下面這樣的代碼,假設被選擇的div元素有5000個,則要循環(huán)訪問10000個節(jié)點:
jQuery('div').css('height', 300).css('width', 200);
而在我的想法中,在一個“事務”中,可以如數(shù)據(jù)庫的操作一般,通過保存所有的操作,在“提交事務”的時候統(tǒng)一進行,將10000次節(jié)點訪問,減少至5000次,相當于提升了“1倍”的性能。
簡單實現(xiàn)
“事務”式的jQuery操作中,提供2個函數(shù):
begin:打開一個“事務”,返回一個事務的對象。該對象擁有jQuery的所有函數(shù),但是調用函數(shù)并不會立刻生效,只有在“提交事務”后才會生效。
commit:提交一個“事務”,保證所有事先調用過的函數(shù)都生效,交返回原本的jQuery對象。
實現(xiàn)起來也很方便:
創(chuàng)建一個“事務對象”,復制jQuery.fn上所有函數(shù)到該對象中。
當調用某個函數(shù)時,在預先準備好的“隊列”中添加調用的函數(shù)名和相關參數(shù)。
當提交事務時,對被選擇的元素進行一次遍歷,對遍歷中的每個節(jié)點應用“隊列”中的所有函數(shù)。
簡單地代碼如下:
復制代碼 代碼如下:

var slice = Array.prototype.slice;
jQuery.fn.begin = function() {
var proxy = {
_core: c,
_queue: []
},
key,
func;
//復制jQuery.fn上的函數(shù)
for (key in jQuery.fn) {
func = jQuery.fn[key];
if (typeof func == 'function') {
//這里會因為for循環(huán)產生key始終是最后一個循環(huán)值的問題
//因此必須使用一個閉包保證key的有效性(LIFT效應)
(function(key) {
proxy[key] = function() {
//將函數(shù)調用放到隊列中
this._queue.push([key, slice.call(arguments, 0)]);
return this;
};
})(key);
}
}
//避免commit函數(shù)也被攔截
proxy.commit = jQuery.fn.commit;
return proxy;
};
jQuery.fn.commit = function() {
var core = this._core,
queue = this._queue;
//僅一個each循環(huán)
core.each(function() {
var i = 0,
item,
jq = jQuery(this);
//調用所有函數(shù)
for (; item = queue[i]; i++) {
jq[item[0]].apply(jq, item[1]);
}
});
return this.c;
};

測試環(huán)境
測試使用以下條件:
5000個div放在一個容器(<div id="container"></div>)中。
使用$('#container>div')選擇這5000個div。
每個div要求設置一個隨機背景色(randomColor函數(shù)),和800px以下的隨機寬度(randomWidth函數(shù))。
參加測試的調用方法有3個:
正常使用法:
復制代碼 代碼如下:

$('#container>div')
.css('background-color', randomColor)
.css('width', randomWidth);

單次循環(huán)法:
復制代碼 代碼如下:

$('#container>div').each(function() {
$(this).css('background-color', randomColor).css('width', randomWidth);
});

事務法:
復制代碼 代碼如下:

$('#container>div')
.begin()
.css('background-color', randomColor)
.css('width', randomWidth)
.commit();

對象賦值法:
復制代碼 代碼如下:

$('#container>div').css({
'background-color': randomColor,
'width': randomWidth
});

測試瀏覽器選擇Chrome 8系列(用IE測就直接掛了)。
悲傷的結果
原本的預測結果是,單次循環(huán)法的效率遠高于正常使用法,同時事務法雖然比單次循環(huán)法慢一些,但應該比正常使用法更快,而對象賦值法其實是jQuery內部支持的單次循環(huán)法,效率應該是最高的。
然而遺憾的是,結果如下:
正常使用法 單次循環(huán)法 事務法 對象賦值法
18435ms 18233ms 18918ms 17748ms
從結果上看,事務法成了最慢的一種方法。同時單次循環(huán)與正常使用并沒有明顯的優(yōu)勢,甚至依賴jQuery內部實現(xiàn)的對象賦值法也沒有拉開很大的差距。
由于5000個元素的操作已經(jīng)是非常龐大的循環(huán),如此龐大的循環(huán)也沒能拉開性能的差距,平時最常用的10個左右的元素操作更不可能有明顯的優(yōu)勢,甚至還可能將劣勢擴大化。
究其原因,由于本身單次循環(huán)法就沒有明顯的性能提升,因此依賴于單次循環(huán),并是在單次循環(huán)之上進行外部構建的事務法,自然是在單次循環(huán)的基礎上還需要額外增加創(chuàng)建事務對象、保存函數(shù)隊列、遍歷函數(shù)隊列等開銷,結果敗給正常使用法也在情理之中。
至此,也算是可以宣布模仿“事務”的優(yōu)化之道的失敗。但是對這個結果卻還能進一步地分析。
性能在哪里
首先,從代碼的使用上來分析,將正常使用法和測試中最快的對象賦值法進行比較,可以說兩者的差距僅在于循環(huán)的元素個數(shù)的不同(這里拋開了jQuery的內部問題,事實上jQuery.access的糟糕實現(xiàn)也確實有拖對象賦值法后腿之嫌,好在并不嚴重),正常使用法是10000個元素,對象賦值法是5000個元素。因此可以簡單地認為,18435 - 17748 = 687ms是循環(huán)5000個元素的耗時,這占到整個執(zhí)行過程的3.5%左右,并不是整個執(zhí)行過程的主干,其實真的沒有優(yōu)化的必要。

那么另外96.5%的開銷去了哪里呢?謹記Doglas的一句話,“事實上Javascript并不慢,慢的是DOM的操作”。其實剩下96.5%的開銷中,除去函數(shù)調用等基本的消耗,至少有95%的時間是用在了DOM元素的樣式被改變后的重新渲染之上。

發(fā)現(xiàn)了這個事實之后,其實也就有了更正確的優(yōu)化方向,也是前端性能中的基本原則之一:在修改大量子元素時,先將根父DOM節(jié)點移出DOM樹。因此如果使用以下的代碼再進行測試:
復制代碼 代碼如下:

//沒有重用$('#container')已經(jīng)很糟糕了
$('#container').detach().find('div')
.css('background-color', randomColor)
.css('width', randomWidth);
$('#container').appendTo(document.body);

測試結果始終停留在900ms左右,與前面的數(shù)據(jù)完全不在一個數(shù)量級之上,真正的優(yōu)化成功。

教訓和總結
千萬要找到正確的性能瓶頸再進行優(yōu)化,盲目的猜測只會導致走上錯誤而偏激的道路。
數(shù)據(jù)說話,數(shù)據(jù)面前誰也別說話!
不認為“事務”這個方向是錯誤的,如果jQuery原生就能支持“事務”這樣的概念,會不會有其他的點可以優(yōu)化?比如一個事務自動會將父元素脫離出DOM樹之類的……

相關文章

  • jQuery代碼優(yōu)化之基本事件

    jQuery代碼優(yōu)化之基本事件

    jQuery對事件系統(tǒng)的抽象與優(yōu)化也是它的一大特色。本文僅從事件系統(tǒng)入手,簡要分析一下jQuery為什么提供mouseenter和mouseleave事件,它們與標準的mouseover、mouseout事件有什么區(qū)別
    2011-11-11
  • 基于jquery實現(xiàn)下拉框美化特效

    基于jquery實現(xiàn)下拉框美化特效

    這篇文章主要為大家詳細介紹了基于jquery實現(xiàn)下拉框美化特效的示例代碼,以一個完整的實例進行分析講解,感興趣的小伙伴們可以參考一下
    2016-02-02
  • checkbox 選中一個另一個checkbox也會選中的實現(xiàn)代碼

    checkbox 選中一個另一個checkbox也會選中的實現(xiàn)代碼

    本文給大家?guī)砹薱heckbox選擇器之checkbox 選中一個另一個checkbox也會選中的實現(xiàn)代碼 ,非常不錯,有需要的可以參考下
    2016-07-07
  • 利用jQuery來動態(tài)為屬性添加或者刪除屬性的簡單方法

    利用jQuery來動態(tài)為屬性添加或者刪除屬性的簡單方法

    下面小編就為大家?guī)硪黄胘Query來動態(tài)為屬性添加或者刪除屬性的簡單方法。小編覺的挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • jquery中push()的用法(數(shù)組添加元素)

    jquery中push()的用法(數(shù)組添加元素)

    這篇文章主要介紹了jquery的push使用方法,可向數(shù)組的末尾添加一個或多個元素,并返回新的長度,需要的朋友可以參考下
    2014-11-11
  • jQuery Chart圖表制作組件Highcharts用法詳解

    jQuery Chart圖表制作組件Highcharts用法詳解

    這篇文章主要介紹了jQuery Chart圖表制作組件Highcharts用法,詳細分析了Highcharts插件的功能與具體使用技巧及相關注意事項,需要的朋友可以參考下
    2016-06-06
  • jQuery EasyUI API 中文文檔 - Spinner微調器使用

    jQuery EasyUI API 中文文檔 - Spinner微調器使用

    jQuery EasyUI API 中文文檔 - Spinner微調器使用,需要的朋友可以參考下。
    2011-10-10
  • 影響jQuery使用的14個方面

    影響jQuery使用的14個方面

    jQuery的插件提供了一個很好的方法,節(jié)省了時間和簡化了開發(fā),避免程序員從頭開始編寫每個組件。但是,插件也將一個不穩(wěn)定因素引入代碼中。一個好的插件節(jié)省了無數(shù)的開發(fā)時間,一個質量不好的插件會導致修復錯誤的時間比實際從頭 開始編寫組件的時間還長。
    2014-09-09
  • jQuery源碼分析-05異步隊列 Deferred 使用介紹

    jQuery源碼分析-05異步隊列 Deferred 使用介紹

    異步隊列是一個鏈式對象,增強對回調函數(shù)的管理和調用,用于處理異步任務
    2011-11-11
  • jquery解析json格式數(shù)據(jù)的方法(對象、字符串)

    jquery解析json格式數(shù)據(jù)的方法(對象、字符串)

    這篇文章主要介紹了jquery解析json格式數(shù)據(jù)的方法,包括針對json對象及json字符串的解析技巧,并附帶了完整的jQuery解析json數(shù)據(jù)示例,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-11-11

最新評論

平乡县| 盖州市| 榕江县| 句容市| 得荣县| 北海市| 耿马| 芜湖市| 咸宁市| 年辖:市辖区| 南开区| 阳东县| 桂阳县| 安图县| 台南市| 鸡泽县| 南汇区| 太湖县| 连江县| 突泉县| 体育| 苗栗市| 湘潭市| 时尚| 安陆市| 南平市| 堆龙德庆县| 逊克县| 正蓝旗| 新建县| 河池市| 海伦市| 通许县| 阳城县| 闽清县| 九寨沟县| 多伦县| 望江县| 平舆县| 库尔勒市| 上蔡县|