--- a/busui/owa/modules/base/js/includes/jquery/jQote2/jqote.benchmark.htm +++ b/busui/owa/modules/base/js/includes/jquery/jQote2/jqote.benchmark.htm @@ -1,1 +1,317 @@ - +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> +<html> + <head> + <meta content="text/html; charset=UTF-8" http-equiv="Content-Type"> + <title>ECMAScript Templating Benchmarks // aefxx.com</title> + <link type="image/x-icon" href="favicon.ico" rel="Shortcut Icon"> + <link rel="stylesheet" href="external/styles.css" type="text/css"/> + <script src="external/jquery-1.4.2.min.js" type="text/javascript"></script> + <script src="external/jquery.benchmark.js" type="text/javascript"></script> + <script src="external/jquery.flot.min.js" type="text/javascript"></script> + <script src="external/jquery.mustache.js" type="text/javascript"></script> + <script src="external/jquery.tempest.js" type="text/javascript"></script> + <script src="external/jquery.tmpl.js" type="text/javascript"></script> + <script src="external/underscore.js" type="text/javascript"></script> + <script src="external/jquery.srender.js" type="text/javascript"></script> + <script src="external/jquery.nano.js" type="text/javascript"></script> + <script src="jquery.jqote2.min.js" type="text/javascript"></script> + </head> + <body> + <h1>ECMAScript Templating Benchmarks</h1> + <hr/> + <h2>©2010 aefxx // powered by jQuery // idea taken from Brian Landau</h2> + <ul id="contestants"> + <li> + <p><input type="checkbox" name="contestant" value="srender"/> srender</p> + <ul class="progress srender"></ul> + <p class="number"></p> + </li> + <li> + <p><input type="checkbox" name="contestant" value="mustache_js"/> mustache.js</p> + <ul class="progress mustache_js"></ul> + <p class="number"></p> + </li> + <li> + <p><input type="checkbox" name="contestant" value="underscore"/> Underscore</p> + <ul class="progress underscore"></ul> + <p class="number"></p> + </li> + <li> + <p><input type="checkbox" name="contestant" value="jqote2"/> jQote2</p> + <ul class="progress jqote2"></ul> + <p class="number"></p> + </li> + <li> + <p><input type="checkbox" name="contestant" value="tempest"/> Tempest</p> + <ul class="progress tempest"></ul> + <p class="number"></p> + </li> + <li> + <p><input type="checkbox" name="contestant" value="nano"/> nano</p> + <ul class="progress nano"></ul> + <p class="number"></p> + </li> + <li> + <p><input type="checkbox" name="contestant" value="tmpl"/> jQuery templating</p> + <ul class="progress tmpl"></ul> + <p class="number"></p> + </li> + <li> + <input type="checkbox" name="check" value="0"/> Check all + </li> + <li> + <button id="run">RUN</button> +   Cycles:  + 5x <input type="radio" name="cycles" value="5" checked="checked"/> + 10x <input type="radio" name="cycles" value="10"/> + 25x <input type="radio" name="cycles" value="25"/> + 50x <input type="radio" name="cycles" value="50"/> +   Types:  + Simple <input type="checkbox" name="simple_test" value="1" checked="checked"/> + Loop <input type="checkbox" name="loop_test" value="2" checked="checked"/> + </li> + </ul> + <h2>█ Single Passed Run    Median in ms [Arithm. AVG in ms]</h2> + <div id="placeholder"></div> + <script type="text/javascript"> + var CYCLES = $('input:radio:checked').val(), + CONVERSIONS = 1000, + RUN_LEAP = Math.round(CONVERSIONS * 0.5), + contestants = {}; + + function shuffle(v) { + for ( var j, x, i = v.length; i; j = parseInt(Math.random() * i), x = v[--i], v[i] = v[j], v[j] = x ); + return v; + }; + + function mean(array) { + if ( !array.length ) return 0; + + var sum = 0; + for ( var i=0; i < array.length; i++ ) + sum += parseFloat(array[i], 4); + return (1/array.length) * sum; + } + + function median(array) { + if ( !array.length ) return 0; + + var s = array.sort(function(a, b) {return a - b;}).length; + return s % 2 ? + array[(s-1)/2] : (array[(s/2)-1] + array[s/2]) / 2; + } + + function plot(cons) { + var data = [], i = 1; + + for ( key in cons ) { + var result = { + median: median(cons[key].results).toPrecision(2)*1000, + mean: mean(cons[key].results).toPrecision(2)*1000 + }; + + data.push({ + label: cons[key].name, + data: [[i++, result.median], [i++,null]], + color: cons[key].color, + bars: { + show: true, + barWidth: 1, + lineWidth: 1, + fill: 1, + colors: cons[key].color + } + }); + + if ( cons[key].results.length ) + cons[key].number.text(result.median+' ms ['+result.mean+' ms]'); + } + + $.plot($('#placeholder'), data, { + xaxis: { ticks: [[1.5, 'Srender'], [3.5, 'mustache.js'], [5.5, 'Underscore'], [7.5, 'jQote2'], [9.5, 'Tempest'], [11.5, 'nano']], autoscaleMargin: .02 }, + yaxis: { min: 10, max: 150 }, + legend: { position: 'ne' }, + grid: { backgroundColor: '#ffffff' } + }); + } + + $(function() { + var benchmarks = { + srender: { + simple: function() {$.srender(this.simple, payload.simple);}, + loop: function() {$.srender(this.loop, payload.loop);} + }, + mustache_js: { + simple: function() {$.mustache(this.simple, payload.simple);}, + loop: function() {$.mustache(this.loop, payload.loop);} + }, + underscore: { + simple: function() {this.simple(payload.simple);}, + loop: function() {this.loop(payload.loop);} + }, + jqote2: { + simple: function() {$.jqote(this.simple, payload.simple);}, + loop: function() {$.jqote(this.loop, payload.loop);} + }, + tempest: { + simple: function() {$.tempest(this.simple, payload.simple);}, + loop: function() {$.tempest(this.loop, payload.loop);} + }, + nano: { + simple: function() {$.nano(this.simple, payload.simple);}, + loop: function() { + var nano = {comments: '', header: payload.loop.header}; + for ( var i=0; i < payload.loop.comments.length; i++ ) + nano.comments += $.nano(this.loop.comment, payload.loop.comments[i]); + + $.nano(this.loop.container, nano); + } + }, + tmpl: { + simple: function() { + $.templates.simple.call(payload.simple, jQuery, { + data: payload.simple, + index: 0, + dataItem: payload.simple, + options: {} + }); + }, + loop: function() { + $.templates.loop.call(payload.loop, jQuery, { + data: payload.loop, + index: 0, + dataItem: payload.loop, + options: {} + }); + } + } + }; + + var templates = { + mustache_js: { + simple: '<div class="test"><h2>This is a test of {{name}}</h2><p>The homepage is <a href="{{url}}">{{url}}</a>.</p><p>The sources is: {{source}}</p></div>', + loop: '<div class="comments"><h3>{{header}}</h3><ul>{{#comments}}<li class="comment"><h5>{{name}}</h5><p>{{body}}</p></li>{{/comments}}</ul></div>' + }, + underscore: { + simple: _.template('<div class="test"><h2>This is a test of <%= name %></h2><p>The homepage is <a href="<%= url %>"><%= url %></a>.</p><p>The sources is: <%= source %></p></div>'), + loop: _.template('<div class="comments"><h3><%= header %></h3><ul><% _.each(comments, function(comment){ %><li class="comment"><h5><%= comment.name %></h5><p><%= comment.body %></p></li><% }); %></ul></div>') + }, + srender: { + simple: '<div class="test"><h2>This is a test of <%= name %></h2><p>The homepage is <a href="<%= url %>"><%= url %></a>.</p><p>The sources is: <%= source %></p></div>', + loop: '<div class="comments"><h3><%= header %></h3><ul><% $.each(comments, function(i, comment){ %><li class="comment"><h5><%= comment.name %></h5><p><%= comment.body %></p></li><% }); %></ul></div>' + }, + jqote2: { + simple: $.jqotec('#jqote2_simple'), + loop: $.jqotec('#jqote2_loop') + }, + tempest: { + simple: $.tempest('simple', '<div class="test"><h2>This is a test of {{name}}</h2><p>The homepage is <a href="{{url}}">{{url}}</a>.</p><p>The sources is: {{source}}</p></div>') && 'simple', + loop: $.tempest('loop', '<div class="comments"><h3>{{header}}</h3><ul>{% for comment in comments %}<li class="comment"<h5>{{comment.name}}</h5><p>{{comment.body}}</p></li>{% endfor %}</ul></div>') && 'loop' + }, + nano: { + simple: '<div class="test"><h2>This is a test of {name}</h2><p>The homepage is <a href="{url}">{url}</a>.</p><p>The sources is: {source}</p></div>', + loop: { + comment: '<li class="comment"><h5>{name}</h5><p>{body}</p></li>', + container: '<div class="comments"><h3>{header}</h3><ul>{comments}</ul></div>' + } + } + }; + + $.templates.simple = $.tmpl('<div class="test"><h2>This is a test of ${name}</h2><p>The homepage is <a href="${url}">${url}</a>.</p><p>The sources is: ${source}</p></div>'); + $.templates.loop = $.tmpl('<div class="comments"><h3>${header}</h3><ul>{{each(i,comment) comments}}<li class="comment"><h5>${comment.name}</h5><p>${comment.body}</p></li>{{/each}}</ul></div>'); + + var payload = { + simple: { + name: 'foo', + url: 'http://foo.bar/foo', + source: 'http://foo.bar/jquery.foo.js' + }, + loop: { + header: "My Post Comments", + comments: [ + {name: "Joe", body: "Thanks for this post!"}, + {name: "Sam", body: "Thanks for this post!"}, + {name: "Heather", body: "Thanks for this post!"}, + {name: "Kathy", body: "Thanks for this post!"}, + {name: "George", body: "Thanks for this post!"} + ] + } + }; + + var color = { + mustache_js: '#8f04a8', + underscore: '#cd0074', + srender: '#5b4cd8', + jqote2: '#70e500', + tempest: '#0d3349', + nano: '#fff800', + tmpl: '#00f8ff' + }; + + $('input[name=check]').click(function() { + var checked = this.checked; + + $('input[name=contestant]').each(function() { + this.checked = checked; + }); + }); + + $('input[name=contestant]').each(function(i) { + var key = this.value; + + contestants[key] = { + name: key, + results: [], + input: $(this), + color: color[key], + number: $('p.number', $(this).parents('li')[0]), + progress: $('ul.progress', $(this).parents('li')[0]), + templates: templates[key], + benchmarks: benchmarks[key] + }; + }).click(function() { + $('input[name=check]')[0].checked = false; + }); + + $('#run').click(function() { + CYCLES = $('input:radio:checked').val(); + $('ul.progress, p.number').empty(); + $(this).trigger('benchmark'); + + }).bind('benchmark', function() { + var cons = shuffle($('input[name=contestant]:checked').toArray()), + runs = cons.length; + + if ( !runs ) return; + + var test_run = setInterval(function() { + var contestant = null; + + if ( !(contestant = cons.shift()) ) return; + + if ( $('input[name=simple_test]:checked').length ) + $.benchmark(CONVERSIONS, contestants[contestant.value], 'simple'); + if ( $('input[name=loop_test]:checked').length ) + $.benchmark(CONVERSIONS, contestants[contestant.value], 'loop'); + + contestants[contestant.value].progress.append('<li/>'); + }, RUN_LEAP); + + setTimeout(function() { + clearInterval(test_run); + ( --CYCLES ) ? $('#run').trigger('benchmark') : plot(contestants); + }, RUN_LEAP * runs + 1500); + }); + }); + </script> + </body> + + <script type="text/x-jqote-template" id="jqote2_simple"> + <![CDATA[<div class="test"><h2>This is a test of <%= this.name %></h2><p>The homepage is <a href="<%= this.url %>"><%= this.url %></a>.</p><p>The sources is: <%= this.source %></p></div>]]> + </script> + + <script type="text/x-jqote-template" id="jqote2_loop"> + <![CDATA[<div class="comments"><h3><%= this.header %></h3><ul><% $.each(this.comments, function(i, comment){ %><li class="comment"><h5><%= comment.name %></h5><p><%= comment.body %></p></li><% }); %></ul></div>]]> + </script> +</html> +