91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

jQuery優化失敗的示例分析

發布時間:2021-11-02 17:49:02 來源:億速云 閱讀:139 作者:柒染 欄目:web開發

本篇文章給大家分享的是有關jQuery優化失敗的示例分析,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

我經常抱怨jQuery的DOM操作性能并不優秀,并且經常嘗試用一些方法去進行優化,但是越是優化,越是沮喪地發現jQuery其實已經做得很好,從使用者的角度能夠進行的優化實在有限(這并不意味著jQuery的性能是優秀的, 反之只能說它是一個相對封閉的庫,無法從外部介入進行優化)。這篇文章就記錄一次失敗的優化經歷。

優化思想

這一次優化的思想來自于數據庫。在數據庫優化的時候,我們常會說將大量的操作放在一個事務中一起提交,能有效提高效率。雖然對數據庫不了解的我并不知道其原因,但是事務的思想卻為我指明了方向(雖然是錯的)。

因此我嘗試將事務這一概念引入到jQuery中,通過打開和提交事務,從外部對jQuery進行一些優化,其最重要的在于減少each函數的循環次數。

眾所周知,jQuery的DOM操作,以get all, set first為標準,其中用于設置DOM屬性/樣式的操作,幾乎都是對選擇出來的元素的一次遍歷,jQuery.access函數就是其中最核心的部分,其中用于循環的代碼如下:

// 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函數就是這樣的:

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個,則要循環訪問10000個節點:

jQuery('div').css('height', 300).css('width', 200);

而在我的想法中,在一個事務中,可以如數據庫的操作一般,通過保存所有的操作,在提交事務的時候統一進行,將10000次節點訪問,減少至5000次,相當于提升了1倍的性能。

簡單實現

事務式的jQuery操作中,提供2個函數:

 ◆  begin:打開一個事務,返回一個事務的對象。該對象擁有jQuery的所有函數,但是調用函數并不會立刻生效,只有在提交事務后才會生效。

 ◆ commit:提交一個事務,保證所有事先調用過的函數都生效,交返回原本的jQuery對象。

實現起來也很方便:

 ◆ 創建一個事務對象,復制jQuery.fn上所有函數到該對象中。

 ◆ 當調用某個函數時,在預先準備好的隊列中添加調用的函數名和相關參數。

 ◆ 當提交事務時,對被選擇的元素進行一次遍歷,對遍歷中的每個節點應用隊列中的所有函數。

簡單地代碼如下:

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

測試環境

測試使用以下條件:

 ◆ 5000個div放在一個容器(div id="container"/div)中。

 ◆使用$(#containerdiv)選擇這5000個div。

 ◆每個div要求設置一個隨機背景色(randomColor函數),和800px以下的隨機寬度(randomWidth函數)。

參加測試的調用方法有3個:

 ◆正常使用法:

$('#containerdiv')      .css('background-color', randomColor)      .css('width', randomWidth);

 ◆單次循環法:

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

 ◆事務法:

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

 ◆對象賦值法:

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

測試瀏覽器選擇Chrome 8系列(用IE測就直接掛了)。

悲傷的結果

原本的預測結果是,單次循環法的效率遠高于正常使用法,同時事務法雖然比單次循環法慢一些,但應該比正常使用法更快,而對象賦值法其實是jQuery內部支持的單次循環法,效率應該是***的。

然而遺憾的是,結果如下:

正常使用法單次循環法事務法對象賦值法
18435ms18233ms18918ms17748ms

從結果上看,事務法成了最慢的一種方法。同時單次循環與正常使用并沒有明顯的優勢,甚至依賴jQuery內部實現的對象賦值法也沒有拉開很大的差距。

由于5000個元素的操作已經是非常龐大的循環,如此龐大的循環也沒能拉開性能的差距,平時最常用的10個左右的元素操作更不可能有明顯的優勢,甚至還可能將劣勢擴大化。

究其原因,由于本身單次循環法就沒有明顯的性能提升,因此依賴于單次循環,并是在單次循環之上進行外部構建的事務法,自然是在單次循環的基礎上還需要額外增加創建事務對象、保存函數隊列、遍歷函數隊列等開銷,結果敗給正常使用法也在情理之中。

至此,也算是可以宣布模仿事務的優化之道的失敗。但是對這個結果卻還能進一步地分析。

性能在哪里

首先,從代碼的使用上來分析,將正常使用法和測試中最快的對象賦值法進行比較,可以說兩者的差距僅在于循環的元素個數的不同(這里拋開了jQuery的內部問題,事實上jQuery.access的糟糕實現也確實有拖對象賦值法后腿之嫌,好在并不嚴重),正常使用法是10000個元素,對象賦值法是5000個元素。因此可以簡單地認為,18435 17748 = 687ms是循環5000個元素的耗時,這占到整個執行過程的3.5%左右,并不是整個執行過程的主干,其實真的沒有優化的必要。

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

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

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

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

教訓和總結

 ◆千萬要找到正確的性能瓶頸再進行優化,盲目的猜測只會導致走上錯誤而偏激的道路。

 ◆ 數據說話,數據面前誰也別說話!

 ◆不認為事務這個方向是錯誤的,如果jQuery原生就能支持事務這樣的概念,會不會有其他的點可以優化?比如一個事務自動會將父元素脫離出DOM樹之類的

以上就是jQuery優化失敗的示例分析,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

宜阳县| 蓝田县| 乳源| 公主岭市| 平潭县| 儋州市| 吉首市| 湟中县| 吴堡县| 易门县| 六盘水市| 横山县| 屯昌县| 丹棱县| 大丰市| 南涧| 班戈县| 宜黄县| 武宣县| 南皮县| 高密市| 南郑县| 新宾| 涞源县| 怀宁县| 浮梁县| 泌阳县| 万载县| 苏尼特右旗| 金湖县| 隆化县| 鹤岗市| 丰原市| 甘谷县| 乌兰县| 稻城县| 土默特右旗| 武乡县| 辛集市| 安陆市| 宁城县|