jQuery选择器的性能测试

来源:岁月联盟 编辑:exp 时间:2012-02-11

在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();$('div')$.lt();
* @example: $.bm('$('div')'); - 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 divideBy - You can switch back to milliseconds by specifying this as 1
     */ 
    $.extend($, { 
        time: function (divideBy) { 
            return ~~(+ (new Date().getTime() / (typeof divideBy === 'undefined' ? 1000 : divideBy))); 
        } 
    }); 
 
    /**
     * 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();$('div')$.lt();
* @example: $.bm('$('div')'); - 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 divideBy - You can switch back to milliseconds by specifying this as 1
  */
 $.extend($, {
        time: function (divideBy) {
   return ~~(+ (new Date().getTime() / (typeof divideBy === 'undefined' ? 1000 : divideBy)));
  }
    });

 /**
  * 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++){ 
        $(".testdiv");   
    } 
    console.log("$('.testdiv'):", $.lt()); 
    //$("id class");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $("#test .testdiv");     
    } 
    console.log("$('#test .testdiv'):", $.lt()); 
    //$("class","id");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $(".testdiv", "#test");  
    } 
    console.log("$('.testdiv', '#test'):", $.lt()); 
    //$("id").find("class");  
    $.lt(); 
    for(i=1; i<99999; i++){ 
        $("#test").find(".testdiv");     
    } 
    console.log("$('#test').find('.testdiv'):", $.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++){
  $(".testdiv"); 
 }
 console.log("$('.testdiv'):", $.lt());
 //$("id class");
 $.lt();
 for(i=1; i<99999; i++){
  $("#test .testdiv"); 
 }
 console.log("$('#test .testdiv'):", $.lt());
 //$("class","id");
 $.lt();
 for(i=1; i<99999; i++){
  $(".testdiv", "#test"); 
 }
 console.log("$('.testdiv', '#test'):", $.lt());
 //$("id").find("class");
 $.lt();
 for(i=1; i<99999; i++){
  $("#test").find(".testdiv"); 
 }
 console.log("$('#test').find('.testdiv'):", $.lt());
});


html的代码如下:


[html]
<div></div><div></div><div></div>    
<div></div><div></div><div></div>    
<div></div><div></div><div></div>    
<div></div><div></div><div></div>           
<div></div><div></div><div></div>      
<div id="test"> 
    <div class="testdiv"></div> 
    <div></div><div></div><div></div> 
    <div></div><div></div><div></div>    
    <div></div><div></div><div></div>    
    <div></div><div></div><div></div>    
    <div></div><div></div><div></div>    
    <div></div><div></div><div></div>    
    <div></div><div></div><div></div>    
    <div class="testdiv"></div> 
    <div class="testdiv"></div> 
    <div class="testdiv"></div> 
</div> 
<div></div><div></div><div></div> 
<div></div><div></div><div></div> 
<div></div><div></div><div></div> 
<div></div><div></div><div></div> 
<div></div><div></div><div></div> 
<div></div><div></div><div></div> 
<div class="testdiv"></div> 
<div class="testdiv"></div> 
<div class="testdiv"></div> 
<div></div><div></div><div></div>  
<div></div><div></div><div></div>  
<div></div><div></div><div></div>  
<div></div><div></div><div></div>         
<div></div><div></div><div></div>    
<div id="test">
    <div class="testdiv"></div>
    <div></div><div></div><div></div>
    <div></div><div></div><div></div>  
    <div></div><div></div><div></div>  
    <div></div><div></div><div></div>  
    <div></div><div></div><div></div>  
    <div></div><div></div><div></div>  
    <div></div><div></div><div></div>  
    <div class="testdiv"></div>
    <div class="testdiv"></div>
    <div class="testdiv"></div>
</div>
<div></div><div></div><div></div>
<div></div><div></div><div></div>
<div></div><div></div><div></div>
<div></div><div></div><div></div>
<div></div><div></div><div></div>
<div></div><div></div><div></div>
<div class="testdiv"></div>
<div class="testdiv"></div>
<div class="testdiv"></div>

 


Chrome的测试结果:

 /

 

FireFox的测试结果:

 /

 

可以看到,jQuery的选择器在性能和js还是有不少的差距。

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

如果针对特定的class进行选择时,

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

而$("id class") 和 $("class","id")两个方法在两个浏览器之间不同的情况。

 


Deom

 摘自 简生的代码备忘录