上一张图,很多人都看过的
地址:http://aui.github.io/artTemplate/test/test-speed.html
这个地址是在看artTemplate的时候看到的,很早都看过但是没去研究为什么artTemplate为什么那么快,其他的为什么那么慢。最近看underscore的源码,先看了template部分,再想起这张图,我就不服了。凭神马underscore那么慢,基本上就是倒数第二的成绩。我代码写得少,上面那个图是在骗我吗!!!
于是看了下作者的测试代码,也在作者那个页面跑了好几次,结果几乎都差不多,难道事实就是这样的!!!!underscore的渲染速度是垫底的成绩。于是看了看作者的测试代码,其他的不管,只看underscore的。
name: ‘underscoreTemplate‘, tester: function () { var source = document.getElementById(‘underscoreTemplate‘).innerHTML; var fn = _.template(source); for (var i = 0; i < number; i ++) { fn(data); } }
页面上还有一些变量
// 数据量 var length = 100; // 渲染次数 var number = 10000; var data = { list: [] }; for (var i = 0; i < length; i ++) { data.list.push({ index: i, user: ‘<strong style="color:red">糖饼</strong>‘, site: ‘http://www.planeart.cn‘, weibo: ‘http://weibo.com/planeart‘, QQweibo: ‘http://t.qq.com/tangbin‘ }); };
模板代码
<!-- underscore 的模板 --> <script id="underscoreTemplate" type="text/tmpl"> <ul> <% for (var i = 0, l = list.length; i < l; i ++) { %> <li>用户: <%=list[i].user%>/ 网站:<%=list[i].site%></li> <% } %> </ul> </script>
以上代码貌似都没什么看头,都是正常的使用代码,但是我想说underscore可以这样用var fn = _.template(source,{variable:list});您也可以在 variable 设置里指定一个变量。名外部指定变量名内部就不会使用with,问题就出在这里,测试代码没这样用!!!!
其实underscore内部代码稍加改动就可以去掉with。于是我把代码稍加改动,使用方式稍加改动,以下是改后的代码。 我使用的underscore的版本是1.7.0
// JavaScript micro-templating, similar to John Resig‘s implementation. // Underscore templating handles arbitrary delimiters, preserves whitespace, // and correctly escapes quotes within interpolated code. // NB: `oldSettings` only exists for backwards compatibility. // template本身是一个方法,可以提供三个参数,第一个为模板文本,第二个为对应模板数据,第三个为基本配置信息 //模板函数可以使用 <%= … %>插入变量, 也可以用<% … %>执行任意的 JavaScript 代码、进行HTML转义,使用<%- … %> _.template = function(text, settings, oldSettings) { if (!settings && oldSettings) settings = oldSettings; settings = _.defaults({}, settings, _.templateSettings); // Combine delimiters into one regular expression via alternation. var matcher = RegExp([ (settings.escape || noMatch).source, (settings.interpolate || noMatch).source, (settings.evaluate || noMatch).source ].join(‘|‘) + ‘|$‘, ‘g‘); // Compile the template source, escaping string literals appropriately. var index = 0; var source = "__p+=‘"; //没有设置settings.variable 默认使用对象+. 来取值 var settingObj = !!settings.variable ? ‘‘ : ‘_obj.‘; //几个分组 text.replace(matcher, function(match, escape, interpolate, evaluate, offset) { source += text.slice(index, offset).replace(escaper, escapeChar); index = offset + match.length; if (escape) { //编码 //_obj.XXX source += "‘+\n((__t=(" + settingObj + escape.trim() + "))==null?‘‘:_.escape(__t))+\n‘"; } else if (interpolate) { //取值 //_obj.XXX source += "‘+\n((__t=(" + settingObj + interpolate.trim() + "))==null?‘‘:__t)+\n‘"; } else if (evaluate) { //任意的Javascript source += "‘;\n" + evaluate + "\n__p+=‘"; } // Adobe VMs need the match returned to produce the correct offest. return match; }); source += "‘;\n"; // If a variable is not specified, place data values in local scope. // 据说使用with 性能不咋地,可以使用变量 // with可能会影响性能,并造成难以发现的错误 //if (!settings.variable) source = ‘with(obj||{}){\n‘ + source + ‘}\n‘; //去掉使用with if (!settings.variable) source = ‘ var _obj=obj||{};\n‘ + source + ‘ \n‘; source = "var __t,__p=‘‘,__j=Array.prototype.join," + "print=function(){__p+=__j.call(arguments,‘‘);};\n" + source + ‘return __p;\n‘; try { var render = new Function(settings.variable || ‘obj‘, ‘_‘, source); } catch (e) { e.source = source; throw e; } var template = function(data) { return render.call(this, data, _); }; // Provide the compiled source as a convenience for precompilation. var argument = settings.variable || ‘obj‘; template.source = ‘function(‘ + argument + ‘){\n‘ + source + ‘}‘; return template; };
改动后的代码,加上使用也改动下,指定variable,测试结构大变,修改后测试结构如下图。不是underscore慢,是没用对。不信自己跑一跑 我提供代码。下载地址:test.zip 里面有一个test-speed.html 跑一下就知道结果了。
这是在chrome38中的测试结果
这是在firefox 34中的测试效果
模板引擎基本上都是模板先预编译 fn = _.template(source),然后调用之前得到的函数fn(data)进行最后的渲染。所以模板引擎的速度应该是模板预编编译时间和数据渲染时间之和才对,但是这里只测试了一个渲染数据的时间,明显不够全面。
我也测试了一下编译速度,发现最快的Handlebars,而artTemplate速度基本上处于垫底水平,不信自己测试。最后得出:模板预编译时间加上渲染的速度其实artTemplate并不是想象中那么快,其实和underscore差不多。不信自己测试下。