jQuery選擇器的性能測試

在https://github.com/doomhz/jQuery-Tweaks 上面看到jQuery性能測試工具:

[javascript]
/**
* Doom Tweaks for Javascript Projects
*
* @author Dumitru Glavan
* @version 1.1 (16-JUL-2011)
* @requires jQuery
* @link http://dumitruglavan.com
*
* @example: $.l(4,5,6);
* @example: $.time();
* @example: $.lt();$('p')$.lt();
* @example: $.bm('$('p')'); – benchmark your code
* @example: $.mockAjax({mockUrl: '/ajax_mocks'}); – mock your ajax calls
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
*/ 
(function ($) { 
 
    /**
     * Extend Firebug
     */ 
    if (typeof(console) === 'object') { 
        /**
         * Shortcut function for console.log()
         */ 
        $.extend($, { 
            l: function () { 
                for (var i = 0; i < arguments.length; i++) { 
                    console.log(arguments[i]); 
                } 
            } 
        }); 
    } 
 
    /**
     * Shortcut function for getting timestamp in second (PHP like function time())
     * @param numeric pideBy – You can switch back to milliseconds by specifying this as 1
     */ 
    $.extend($, { 
        time: function (pideBy) { 
            return ~~(+ (new Date().getTime() / (typeof pideBy === 'undefined' ? 1000 : pideBy))); 
        } 
    }); 
 
    /**
     * Shortcut function for logging time to the Firebug console
     * call $.lt() then your code then $.lt() again to get the results
     */ 
    $.extend($, { 
        lt: function () { 
            if (this.ltLastTime == null) { 
                return this.ltLastTime = new Date().getTime(); 
            } 
            var diff = new Date().getTime() – this.ltLastTime; 
            this.ltLastTime = null; 
            $.l(diff); 
            return diff; 
        }, 
        ltLastTime: null 
    }); 
 
    /**
     * Shortcut function for benchmarking a block of code to the Firebug console
     * this function will run your code in a for block to create overflow and push the results into Firebug
     *
     * @param string benchmarkCode – the block of code you want to benchmark
     * @param numeric testTime – the number of FOR cicles
     */ 
    $.extend($, { 
        bm: function (benchmarkCode, testTime) { 
            this.testTime = typeof testTime === 'number' ? testTime : 9999; 
            $.lt(); 
            for (var i = 0;i < this.testTime;i++) { 
                eval(benchmarkCode); 
            } 
            $.lt(); 
        } 
    }); 
         
    /**
     * Mock ajax requests with a prefilter
     *
     */ 
    $.extend($, { 
        mockAjax: function (mockOptions) { 
            mockOptions = $.extend({ 
                mockUrl: '/ajax_mocks' 
            }, mockOptions); 
            $.ajaxPrefilter(function(options, originalOptions, jqXHR) { 
                if (!options.noMock) { 
                    options.url = mockOptions.mockUrl + '?ajax_url=' + encodeURIComponent(options.url); 
                } 
            }); 
        } 
    }); 
     
})(jQuery); 
/**
* Doom Tweaks for Javascript Projects
*
* @author Dumitru Glavan
* @version 1.1 (16-JUL-2011)
* @requires jQuery
* @link http://dumitruglavan.com
*
* @example: $.l(4,5,6);
* @example: $.time();
* @example: $.lt();$('p')$.lt();
* @example: $.bm('$('p')'); – benchmark your code
* @example: $.mockAjax({mockUrl: '/ajax_mocks'}); – mock your ajax calls
*
* Dual licensed under the MIT and GPL licenses:
*   http://www.opensource.org/licenses/mit-license.php
*   http://www.gnu.org/licenses/gpl.html
*
*/
(function ($) {

    /**
  * Extend Firebug
  */
 if (typeof(console) === 'object') {
  /**
   * Shortcut function for console.log()
   */
  $.extend($, {
            l: function () {
                for (var i = 0; i < arguments.length; i++) {
                    console.log(arguments[i]);
                }
            }
        });
 }

 /**
  * Shortcut function for getting timestamp in second (PHP like function time())
  * @param numeric pideBy – You can switch back to milliseconds by specifying this as 1
  */
 $.extend($, {
        time: function (pideBy) {
   return ~~(+ (new Date().getTime() / (typeof pideBy === 'undefined' ? 1000 : pideBy)));
  }
    });

 /**
  * Shortcut function for logging time to the Firebug console
  * call $.lt() then your code then $.lt() again to get the results
  */
 $.extend($, {
        lt: function () {
            if (this.ltLastTime == null) {
                return this.ltLastTime = new Date().getTime();
            }
            var diff = new Date().getTime() – this.ltLastTime;
            this.ltLastTime = null;
            $.l(diff);
            return diff;
        },
        ltLastTime: null
 });

 /**
  * Shortcut function for benchmarking a block of code to the Firebug console
  * this function will run your code in a for block to create overflow and push the results into Firebug
  *
  * @param string benchmarkCode – the block of code you want to benchmark
  * @param numeric testTime – the number of FOR cicles
  */
 $.extend($, {
        bm: function (benchmarkCode, testTime) {
            this.testTime = typeof testTime === 'number' ? testTime : 9999;
            $.lt();
            for (var i = 0;i < this.testTime;i++) {
                eval(benchmarkCode);
            }
            $.lt();
        }
 });
       
    /**
     * Mock ajax requests with a prefilter
     *
     */
    $.extend($, {
        mockAjax: function (mockOptions) {
            mockOptions = $.extend({
                mockUrl: '/ajax_mocks'
            }, mockOptions);
            $.ajaxPrefilter(function(options, originalOptions, jqXHR) {
                if (!options.noMock) {
                    options.url = mockOptions.mockUrl + '?ajax_url=' + encodeURIComponent(options.url);
                }
            });
        }
 });
 
})(jQuery);

 

調試瞭幾組方法:
$("id");

$("class");

$("id class");

$("class","id");

$("id").find("class");

發現並沒有太大的差別;然後查看瞭一下代碼,原來是因為工具函數裡面用瞭eval()方法。

eval()到底有多耗性能?下面做個簡單的測試(調用9998次後所需的時間(ms)):

 

 

通過幾次測試之後,eval()這個方法的所耗時間竟然是$("id")的18–19倍。

這也是為什麼eval()方法需要謹慎使用的原因。

 

如果直接用上面的工具函數來測試jQury方法的性能,實在有點不夠直觀,

所以可以改用下面的方法來測試:

[javascript]
$.lt(); 
for(i=1; i<9999; i++){ 
    $('#test1');     

$.lt(); 
$.lt();
for(i=1; i<9999; i++){
 $('#test1'); 
}
$.lt();當然在使用上沒有封裝好的方法那麼方便,但因為不需要調用eval()方法,所以測出的數值更為直觀。

下面再做幾個測試,js部分代碼如下:

[javascript]
$(document).ready(function () { 
    $.extend($, { 
        lt: function () { 
            if (this.ltLastTime == null) { 
                return this.ltLastTime = new Date().getTime(); 
            } 
            var diff = new Date().getTime() – this.ltLastTime; 
            this.ltLastTime = null; 
            return diff; 
        }, 
        ltLastTime: null 
    }); 
             
    $.lt(); 
    for(i=1; i<99999; i++){ 
        document.getElementById("test"); 
    } 
    console.log("getElementById('test'):", $.lt());      
    //$("id");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $('#test');  
    } 
    console.log("$('#test'):", $.lt()); 
    //$("class");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $(".testp");   
    } 
    console.log("$('.testp'):", $.lt()); 
    //$("id class");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $("#test .testp");     
    } 
    console.log("$('#test .testp'):", $.lt()); 
    //$("class","id");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $(".testp", "#test");  
    } 
    console.log("$('.testp', '#test'):", $.lt()); 
    //$("id").find("class");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $("#test").find(".testp");     
    } 
    console.log("$('#test').find('.testp'):", $.lt()); 
}); 
$(document).ready(function () {
 $.extend($, {
  lt: function () {
   if (this.ltLastTime == null) {
    return this.ltLastTime = new Date().getTime();
   }
   var diff = new Date().getTime() – this.ltLastTime;
   this.ltLastTime = null;
   return diff;
  },
  ltLastTime: null
 });
   
 $.lt();
 for(i=1; i<99999; i++){
  document.getElementById("test");
 }
 console.log("getElementById('test'):", $.lt());  
 //$("id");
 $.lt();
 for(i=1; i<99999; i++){
  $('#test'); 
 }
 console.log("$('#test'):", $.lt());
 //$("class");
 $.lt();
 for(i=1; i<99999; i++){
  $(".testp"); 
 }
 console.log("$('.testp'):", $.lt());
 //$("id class");
 $.lt();
 for(i=1; i<99999; i++){
  $("#test .testp"); 
 }
 console.log("$('#test .testp'):", $.lt());
 //$("class","id");
 $.lt();
 for(i=1; i<99999; i++){
  $(".testp", "#test"); 
 }
 console.log("$('.testp', '#test'):", $.lt());
 //$("id").find("class");
 $.lt();
 for(i=1; i<99999; i++){
  $("#test").find(".testp"); 
 }
 console.log("$('#test').find('.testp'):", $.lt());
});

html的代碼如下:

[html]
<p></p><p></p><p></p>    
<p></p><p></p><p></p>    
<p></p><p></p><p></p>    
<p></p><p></p><p></p>           
<p></p><p></p><p></p>      
<p id="test"> 
    <p class="testp"></p> 
    <p></p><p></p><p></p> 
    <p></p><p></p><p></p>    
    <p></p><p></p><p></p>    
    <p></p><p></p><p></p>    
    <p></p><p></p><p></p>    
    <p></p><p></p><p></p>    
    <p></p><p></p><p></p>    
    <p class="testp"></p> 
    <p class="testp"></p> 
    <p class="testp"></p> 
</p> 
<p></p><p></p><p></p> 
<p></p><p></p><p></p> 
<p></p><p></p><p></p> 
<p></p><p></p><p></p> 
<p></p><p></p><p></p> 
<p></p><p></p><p></p> 
<p class="testp"></p> 
<p class="testp"></p> 
<p class="testp"></p> 
<p></p><p></p><p></p>  
<p></p><p></p><p></p>  
<p></p><p></p><p></p>  
<p></p><p></p><p></p>         
<p></p><p></p><p></p>    
<p id="test">
    <p class="testp"></p>
    <p></p><p></p><p></p>
    <p></p><p></p><p></p>  
    <p></p><p></p><p></p>  
    <p></p><p></p><p></p>  
    <p></p><p></p><p></p>  
    <p></p><p></p><p></p>  
    <p></p><p></p><p></p>  
    <p class="testp"></p>
    <p class="testp"></p>
    <p class="testp"></p>
</p>
<p></p><p></p><p></p>
<p></p><p></p><p></p>
<p></p><p></p><p></p>
<p></p><p></p><p></p>
<p></p><p></p><p></p>
<p></p><p></p><p></p>
<p class="testp"></p>
<p class="testp"></p>
<p class="testp"></p>

 

Chrome的測試結果:

 

 

FireFox的測試結果:

 

 

可以看到,jQuery的選擇器在性能和js還是有不少的差距。

而jQuery以#id選擇器的速度比.class的速度要快很多,

如果針對特定的class進行選擇時,

$("id").find("class");的效率是最高的!

而$("id class") 和 $("class","id")兩個方法在兩個瀏覽器之間不同的情況。

 

Deom

 摘自 簡生的代碼備忘錄
 

發佈留言