全球最快的JS模板引擎
废话不多说,先上测试:

亲测请访问:【在线测试地址】单次结果不一定准确,请多测几次。
tppl 的编译渲染速度是著名的 jQuery 作者 John Resig 开发的 tmpl 的 43 倍!与第二名 artTemplate 也有一倍的差距。
似乎每一个大公司都选择自己开发模板引擎并将其开源,结果就是社区充斥着数不清的引擎,让人眼花缭乱无从选择。随着时间的流逝,越来越多的功能被添加进去,最终让一个强悍的发动机变成了一台臃肿复杂零件生锈的拖拉机。天呐,我就想网页面里插一段 html,你居然要我往每个js文件里再塞进500行代码!
不,事情原本应该更简单。保持代码的简洁高效也意味着让生活更加健康愉悦。
好吧,满脑子装着“封装”或者“模块化”的读者估计有不同的看法。
下面我们来谈谈如何让引擎更加强劲高效。
模板引擎分为两大主要阵营:
- 原生语法
- 自定义模板语法
此两种方案各有各的好,自定义语法相比前者的优点在于,看起来和写起来更加规范简洁,更“像”是一种模板。也能更好的配合编译,并且可以避免用户写出“性能不佳”的代码。部分人认为自定义语法对页面设计人员来说更为友好,这就见仁见智了。而缺点就是通常只能自定义 if else 和 for 循环等简单而有限的逻辑结构,不够强大和灵活。
自定义语法的优化方法有随着语法的不同而不同,但通常最终都是将其转换为原生的语言逻辑结构。这里主要讨论原生语法模板引擎的优化。
对于追求性能的模板引擎来说,有两个显而易见的方向:
- 编译结果缓存
- 编译结果静态化
缓存很好理解,一次编译多次渲染。通常是保存初步正则替换后的字符串中间值,重复渲染时直接拿来使用。
静态指的是,编译模板字符串生成一个字符串拼接的函数,而不是每次创建函数。渲染操作就相当于一次函数调用,代入变量完成字符串拼接并返回。一般引擎优化到这一步时,渲染方面已经没有太大的差距和进步的空间。大家都成了字符串拼接函数,只能在微小的语法层面做优化。这里说一下,相信从事过前端开发的朋友,都“听说”过一个字符串拼接的“快速方法”:将字符串片段 push 进一个数组,最后再 join 返回,性能比直接采用 + 或者 += 字符串要好。注意,这种方法过时了!在现代浏览器以及Node.js中已经不再成立。通过数组连接字符串只是一个“临时解决方案”,随着各大js编译器的优化和进步,直接采用 + 字符串操作,给了一个编译器在语言底层做出优化的机会,大家还是着眼于未来吧。
渲染差距不大时,编译则还存在很多“水分”可以挤出来。当然,一部分模板引擎集成了诸如文件加载、Ajax等高级功能,对其性能方面有要求太高似乎也不太合理。
一般原生语法模板引擎,都采用类似下面的字符串表示:
<h1> <%=title %> </h1>
<% for(var i in content){ %>
<p>第<%=i%>段:<%=content[i]%></p>
<%}%>
而编译操作就是将这一段字符串转换成类似下面的函数:
function(data){
var str = "<h1> "+data.title+" </h1>";
for(var i in data.content){
str += "<p>第"+i+"段:"+data.content[i]+"</p>";
}
return str;
}
通常情况都是改变字符串结构,去掉模板标签,再使用 new Function() 创建函数。
传统传递参数的实现通过遍历数据对象,把对象的名值分离,然后分别把对象成员名称作为new Function的参数名(即变量名),然后使用函数的appley调用方式传给那些参数。
tmpl 则使用了javascript不常用的 with 语句实现。 实现方式很简洁,省去了var这个关键字。tmpl 性能问题就出在 with 上面。javascript 提供的 with 语句,本意是想用来更快捷的访问对象的属性。不幸的是,with语句在语言中的存在,就严重影响了 javascript 引擎的速度,因为它阻止了变量名的词法作用域绑定。
而转换的方法有很多种,一部分采用 split() 截断分析,一部分采用全正则替换,更有强悍的引擎使用词法分析,总之各显神通。
全正则替换的方案只是一长串的 .replace() 链式调用,看起来代码更加美妙,但由于存在中间过渡状态和方法而导致性能不佳。词法分析更不必说,大量的正则拖慢编译速度。编译优化的重点就在,尽量减少中间态,并减少复杂正则表达式的使用。经过实测,split() 截断分析能减少一部分正则,性能更好。
tppl 一开始使用“模板尾标签分割”,即:str.split(”%>”) 的方式,这与 tmpl 的实现方式不谋而合,上面的字符串被分割为6段,然后为每一段使用一次正则替换:
var tpls = ["<h1> <%=title", " </h1>","<% for(var i in content){ ", "<p>第<%=i", "段:<%=content[i]", "</p><%}"];
在后来的性能测试中,发现这种实现方式相比其它引擎,并没有太大的提升。看来只能另辟蹊径了。
经过长时间的冥思苦想,终于发现采用“模板头标签分割”的方式,能大大减少分割结果的数量,但是需要修改模板标签:
<h1> [=:title:] </h1>
[: for(var i in content){ :]
<p>第[=:i:]段:[=:content[i]:]</p>
[:}:]
方括号 [ 与冒号 : 组成的模板标签相比 <% 能更加清晰的区分html代码与js逻辑代码。通过 .split(”[:”) 将模板分割为3段:
var tpls = ["<h1> [=:title:] </h1>", " for(var i in content){ :]<p>第[=:i:]段:[=:content[i]:]</p>", "}:]"];
如此一来正则替换从6次下降到3次,性能提升将近一倍!而且随着代码逻辑结构的不同,性能提升将会更大。
关键的正则表达式:
var line = "'"+"<p>第[=:i:]段:[=:content[i]:]</p>".replace(/\[\=\:(.*?)\:\]/g, "'+$1+'")+"'";
// '<p>第'+i+'段:'+content[i]+'</p>'
tppl 的源码托管在 Github 上,地址:https://github.com/yangjiePro/tppl
如果你还有更好编译优化方法,欢迎讨论!
全球最快的JS模板引擎的更多相关文章
- 全球最快的JS模板引擎:tppl
废话不多说,先上测试: 亲测请访问:[在线测试地址]单次结果不一定准确,请多测几次. tppl 的编译渲染速度是著名的 jQuery 作者 John Resig 开发的 tmpl 的 43 倍!与第二 ...
- JS模板引擎:tppl
全球最快的JS模板引擎:tppl 废话不多说,先上测试: 亲测请访问:[在线测试地址]单次结果不一定准确,请多测几次. tppl 的编译渲染速度是著名的 jQuery 作者 John Resig 开发 ...
- 各种JS模板引擎对比数据(高性能JavaScript模板引擎)
最近做了JS模板引擎测试,拿各个JS模板引擎在不同浏览器上去运行同一程序,下面是模板引擎测试数据:通过测试artTemplate.juicer与doT引擎模板整体性能要有绝对优势: js模板引擎 Ja ...
- 调研js模板引擎
js模板引擎越来越多的得到应用,如今已经出现了几十种js模板引擎,国内各大互联网公司也都开发了自己的js模板引擎(淘宝的kissy template,腾讯的artTemplate,百度的baiduTe ...
- js模板引擎介绍搜集
js模板引擎越来越多的得到应用,如今已经出现了几十种js模板引擎,国内各大互联网公司也都开发了自己的js模板引擎(淘宝的kissy template,腾讯的artTemplate,百度的baiduTe ...
- 浅析js模板引擎
js模板引擎越来越多的得到应用,如今已经出现了几十种js模板引擎,国内各大互联网公司也都开发了自己的js模板引擎(淘宝的kissy template,腾讯的artTemplate,百度的baiduTe ...
- 简易js模板引擎
前面 js 模板引擎有很多很多,我以前经常用 art-template ,有时候也会拿 vue 来当模板引擎用. 直到...... 年初的时候,我还在上个项目组,那时候代码规范是未经允许不能使用 [外 ...
- baiduTemplate.js 百度JS模板引擎
baiduTemplate希望创造一个用户觉得“简单好用”的JS模板引擎 先展示两个例子,然后说说对baidutemplate.js的理解,从而将这一工具加到个人百宝箱里. <script id ...
- android webview 中 js 模板引擎的使用
最近在项目中要求用 webview 展示几个界面, 而后台返回的不是 html 而是 json 数据. 起初用 StringBuilder 一个一个拼 html, 后来感觉太繁琐,拼一个还行,拼多了就 ...
随机推荐
- 编程内功修炼之数据结构—BTree(三)总结
BTree必须通过各种编程约束,使得不脱离BTree的本身特性: 1)BTree关键字插入操作:插入过程中,如果节点关键字达到上限,添加分裂约束,从而控制每个节点的关键字数维持在 t-1~2*t-1内 ...
- [Linux] 修改主机名(hostname)
在Linux命令行下输入hostname,查看当前主机名,如果想修改它,直接在hostname后面加上新主机名即可(注:以下操作都需要root用户执行),如: # hostname newhostna ...
- poj - 1228 - Grandpa's Estate
题意:原来一个凸多边形删去一些点后剩n个点,问这个n个点能否确定原来的凸包(1 <= 测试组数t <= 10,1 <= n <= 1000). 题目链接:http://poj. ...
- Hibernate 、继承关联映射
一个继承树一张表(subclass) 一个继承树一张表是指将一个类和他下面的所有派生类的所有的属性都放在一张表中,举例有Employee这个实体,在他下面分别派生了两个类skill和sell,通过Hi ...
- iOS动画技术笔记
概述 在IOS开发中,实现动画操作的地方有很多,典型的是在视图控制器的segue操作时.在同一个视图控制器类中,加载切换不同的视图时,也需要动画效果,还有一些视图对象有动画效果会更好. 插一句,在IO ...
- POJ1042 Gone Fishing
采用贪心策略. 假设他从1湖泊走到x 湖泊,这还剩下 h*12 - sigma(T1--Tx-1).(单位时间为5分钟).然后再用剩下的时间去钓1-x的湖泊的鱼. 每次都选择最多鱼的湖泊钓. code ...
- windows 环境怎样恢复 (oracle 11g grid) ocr voting 损坏的集群
windows 环境怎样恢复 (oracle 11g grid) ocr voting 损坏的集群 oracle 11g 以后 ocr 能够放到 asm 磁盘上,而ASM的启动依赖于ocr和vo ...
- 黑马程序员 Java基础<十八>---> 网路编程
--------------- ASP.Net+Android+IO开发S..Net培训.期待与您交流! --------------- 第一 概述 一.概述: 1.网络模型:OSI参考模型和TCP ...
- exit函数的妙用
写了一个程序,用来推断一个文件是否存在: #include<stdio.h> main() { FILE *fp; fp = fopen ("/home/wang/my/ct ...
- [hadoop]Cannot create directory /mdrill/tablelist/fact_seller_all_d. Name node is in safe mode.
在执行mdrill创建表的时候报如下异常(蓝色部分为关键): [mdrill@hadoop1101 bin]$ ./bluewhale mdrill create ./create.sql higo ...