JavaScript模板的用途与性能

参考文献1: http://yuguo.us/weblog/javascript-template/ JavaScript模板的用途

我最开始写过一个富交互的页面,其中的JavaScript代码包含了很多html标签。

比如要在一个列表中利用ajax插入一个li的时候,我会直接把数据跟html标签拼接成一句完整的html,然后插入到ul中。无论数据是从服务器端拿回的,或者是从用户的input输入中拿到的——无论哪种方法都是一样。

这个拼接过程放在JavaScript文件中,显得非常不优雅。如果还把style也放在JavaScript中,那数据、结构还有样式整个就是一锅粥了,要维护这样的代码会让人想自杀。最过分的就是把页面上最终要生成的HTML都直接放在服务器端,ajax吐出数据就包含了<li>标签,这样的页面几乎不存在扩展性了,修改一个前台样式都要涉及后台代码的修改。

后来我们知道了不要在JavaScript中对DOM进行style定制,而是只需要在CSS文件中定义好对应的class,然后在JavaScript中使用这个class就好。

接下来我们要做的就是用JavaScript模板把HTML结构(在这个案例中,是<li>标签)也从JavaScript中分离。

市面上的JavaScript模板很多了,以handlebars这个优秀的模板为例吧:

我们在页面的html中定义模板:

<script id="list-template" type="text/x-handlebars-template">
<li>{{title}}</li>
</script>

然后在我们的逻辑JavaScript代码中可以把数据拼接到这一模版中:

var source = $("#list-template").html(); //模板源,一般放在html的script中,这里我们使用jQuery,也可以使用其它方法直接获得内容字符串
var template = Handlebars.compile(source);  //编译生成一个模板template
var context = {title:"This is a todo item"} //获得数据,数据一般从ajax或者input中取得
var html = template(context); //数据+模板=新的html

这就是基本的 用法了,更多逻辑可以参考官方文档:http://handlebarsjs.com/

参考文献2http://cdc.tencent.com/?p=5723

高性能JavaScript模板引擎原理解析

随着 web 发展,前端应用变得越来越复杂,基于后端的 javascript(Node.js) 也开始崭露头角,此时 javascript 被寄予了更大的期望,与此同时 javascript MVC 思想也开始流行起来。javascript 模板引擎作为数据与界面分离工作中最重要一环,越来越受开发者关注,近一年来在开源社区中更是百花齐放,在 Twitter、淘宝网、新浪微博、腾讯QQ空间、腾讯微博等大型网站中均能看到它们的身影。

本文将用最简单的示例代码描述现有的 javascript 模板引擎的原理,包括新一代 javascript 模板引擎 artTemplate 的特性实现原理,欢迎共同探讨。

artTemplate 介绍

artTemplate 是新一代 javascript 模板引擎,它采用预编译方式让性能有了质的飞跃,并且充分利用 javascript 引擎特性,使得其性能无论在前端还是后端都有极其出色的表现。在 chrome 下渲染效率测试中分别是知名引擎 Mustache 与 micro tmpl 的 25 、 32 倍。

速度对比

除了性能优势外,调试功能也值得一提。模板调试器可以精确定位到引发渲染错误的模板语句,解决了编写模板过程中无法调试的痛苦,让开发变得高效,也避免了因为单个模板出错导致整个应用崩溃的情况发生。

artTemplate 这一切都在 1.7kb(gzip) 中实现!

javascript 模板引擎基本原理

虽然每个引擎从模板语法、语法解析、变量赋值、字符串拼接的实现方式各有所不同,但关键的渲染原理仍然是动态执行 javascript 字符串。

关于动态执行 javascript 字符串,本文以一段模板代码举例:

这是一段非常朴素的模板写法,其中,”" 为 closeTag (逻辑语句闭合标签),若 openTag 后面紧跟 “=” 则会输出变量的内容。

HTML语句与变量输出语句被直接输出,解析后的字符串类似:

语法分析完毕一般还会返回渲染方法:

渲染测试:

在上面 render 方法中,模板变量赋值采用了 with 语句,字符串拼接采用数组的 push 方法以提升在 IE6、7 下的性能,jQuery 作者 john 开发的微型模板引擎 tmpl 是这种方式的典型代表,参见: http://ejohn.org/blog/javascript-micro-templating/

由原理实现可见,传统 javascript 模板引擎中留下两个待解决的问题:

1、性能:模板引擎渲染的时候依赖 Function 构造器实现,Function 与 eval、setTimeout、setInterval 一样,提供了使用文本访问 javascript 解析引擎的方法,但这样执行 javascript 的性能非常低下。

2、调试:由于是动态执行字符串,若遇到错误调试器无法捕获错误源,导致模板 BUG 调试变得异常痛苦。在没有进行容错的引擎中,局部模板若因为数据异常甚至可以导致整个应用崩溃,随着模板的数目增加,维护成本将剧增。

artTemplate 高效的秘密

1、预编译

在上述模板引擎实现原理中,因为要对模板变量进行赋值,所以每次渲染都需要动态编译 javascript 字符串完成变量赋值。而 artTemplate 的编译赋值过程却是在渲染之前完成的,这种方式称之为“预编译”。artTemplate 模板编译器会根据一些简单的规则提取好所有模板变量,声明在渲染函数头部,这个函数类似:

这个自动生成的函数就如同一个手工编写的 javascript 函数一样,同等的执行次数下无论 CPU 还是内存占用都有显著减少,性能近乎极限。

值得一提的是:artTemplate 很多特性都基于预编译实现,如沙箱规范与自定义语法等。

2、更快的字符串相加方式

很多人误以为数组 push 方法拼接字符串会比 += 快,要知道这仅仅是 IE6-8 的浏览器下。实测表明现代浏览器使用 += 会比数组 push 方法快,而在 v8 引擎中,使用 += 方式比数组拼接快 4.7 倍。所以 artTemplate 根据 javascript 引擎特性采用了两种不同的字符串拼接方式。

artTemplate 调试模式原理

前端模板引擎不像后端模板引擎,它是动态解析,所以调试器无法定位到错误行号,而 artTemplate 通过巧妙的方式让模板调试器可以精确定位到引发渲染错误的模板语句,例如:

debug

artTemplate 支持两种类型的错误捕获,一是渲染错误(Render Error)与编译错误(Syntax Error)。

1、渲染错误

渲染错误一般是因为模板数据错误或者变量错误产生的,渲染的时候只有遇到错误才会进入调试模式重新编译模板,而不会影响正常的模板执行效率。模板编译器根据模板换行符记录行号,编译后的函数类似:

当执行过程遇到错误,立马抛出异常模板对应的行号,模板调试器再根据行号反查模板对应的语句并打印到控制台。

2、编译错误

编译错误一般是模板语法错误,如不合格的套嵌、未知语法等。由于 artTemplate 没有进行完整的词法分析,故无法确定错误源所在的位置,只能对错误信息与源码进行原文输出,供开发者判断。

开源节流

artTemplate 基于开源协议发布,无论是商业公司还是个人都可以免费在项目中使用,欢迎共同完善。

下载地址:

https://github.com/aui/artTemplate

在线预览:

http://aui.github.com/artTemplate/


参考文献3: http://cnodejs.org/topic/4f16442ccae1f4aa27001109

Javascript模板引擎性能对比及几点优化

浏览器版可直接查看:  JavaScript template language shootoff 

运行性能测试


测试代码在: https://github.com/fengmk2/mk2blog/tree/master/2011/4/js-template-benchmarks 
$ node benchmarks.js


我的测试环境


CPU: 4核 Intel(R) Core(TM) i3 CPU M 330 @ 2.13GHz 
Memory: 4GB 
OS: Ubuntu 10.10 2.6.35-28-generic-pae i686 

我的测试结果


escape延后处理是需要性能代价的。但是这样可以减少业务复杂性。 

场景1:No escape


渲染10万次,最快的是doU, doT, nTenjin(基于tenjin的优化版本), jst_speed;最慢的是tenjin和jade 
doT已经达到百万次级别了,好神速啊! 
!!!新增 @shaunlee 的中国第一速度模板引擎:  jst
@shaunlee看见第一次测试结果后非常不满意,经过优化后,速度已经达到第一梯队了! 
No escape, render 100000 times:



doT running...

use: 0.066 sec, rps: 1515151.5151515151

--------------------------------------------

doU running...

use: 0.064 sec, rps: 1562500

--------------------------------------------

nTenjin running...

use: 0.069 sec, rps: 1449275.3623188403

--------------------------------------------

jqtpl running...

use: 2.059 sec, rps: 48567.26566294317

--------------------------------------------

ejs running...

use: 1.514 sec, rps: 66050.19815059446

--------------------------------------------

haml running...

use: 9.532 sec, rps: 10490.97775912715

--------------------------------------------

jade running...

use: 10.592 sec, rps: 9441.087613293052

--------------------------------------------

jst running...

use: 2.089 sec, rps: 47869.79415988511

--------------------------------------------

jst_speed running...

use: 0.065 sec, rps: 1538461.5384615385

-------------------------------------------

场景2:All escape


性能马上变成浮云了。 
速度高低排名: jst(果然是第一速度), nTenjin, jqtpl, ejs, doT, doU, haml, jade 
对比场景1,可看到doT和doU的escape性能非常差。 
All escape, render 100000 times:



doT running...

use: 3.921 sec, rps: 25503.698036215254

--------------------------------------------

doU running...

use: 3.926 sec, rps: 25471.217524197655

--------------------------------------------

nTenjin running...

use: 1.306 sec, rps: 76569.67840735069

--------------------------------------------

jqtpl running...

use: 3.012 sec, rps: 33200.531208499335

--------------------------------------------

ejs running...

use: 3.539 sec, rps: 28256.569652444192

--------------------------------------------

haml running...

use: 11.098 sec, rps: 9010.632546404757

--------------------------------------------

jade running...

use: 12.676 sec, rps: 7888.9239507731145

--------------------------------------------

jst running...

use: 4.004 sec, rps: 24975.02497502498

--------------------------------------------

jst_speed running...

use: 1.167 sec, rps: 85689.8029134533

--------------------------------------------


  

从tenjin到nTenjin的几点性能优化方法


原文:  https://github.com/QLeelulu/nTenjin/blob/master/README.md 

  • jsTenjin是使用eval来解析的,而nTenjin是使用 new Function 来解析的(速度差别之一)。
  • jsTenjin是使用Array.push来构造字符串的,而nTenjin是使用 String += str 来构造字符串的(速度差别之二)。
  • nTenjin中变量必须由it来指定,例如#{param}要修改为#{it.param},其他和jsTenjin完全一致。

模板引擎优化步骤



  1. 使用new Function 解析;
  2. 直接字符从相加 str += s;
  3. 变量不切换上下文,直接it指定
  4. 高性能的escape



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值