高性能JavaScript模板引擎实现原理详解


Posted in Javascript onFebruary 05, 2015

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

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

artTemplate 介绍

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

高性能JavaScript模板引擎实现原理详解

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

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

javascript 模板引擎基本原理

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

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

高性能JavaScript模板引擎实现原理详解

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

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

高性能JavaScript模板引擎实现原理详解

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

高性能JavaScript模板引擎实现原理详解

渲染测试:

高性能JavaScript模板引擎实现原理详解

在上面 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模板引擎实现原理详解

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

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

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

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

artTemplate 调试模式原理

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

高性能JavaScript模板引擎实现原理详解

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

1、渲染错误

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

高性能JavaScript模板引擎实现原理详解

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

2、编译错误

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

Javascript 相关文章推荐
如何判断图片地址是否失效
Feb 02 Javascript
js 处理URL实用技巧
Nov 23 Javascript
jQuery对表单元素的取值和赋值操作代码
May 19 Javascript
Javascript继承机制的设计思想分享
Aug 28 Javascript
jQuery对Select的操作大集合(收藏)
Dec 28 Javascript
jQuery取得设置清空select选择的文本与值
Jul 08 Javascript
js实现上传图片预览的方法
Feb 09 Javascript
Bootstrap Metronic完全响应式管理模板之菜单栏学习笔记
Jul 08 Javascript
node.js + socket.io 实现点对点随机匹配聊天
Jun 30 Javascript
Bootstrap栅格系统的使用详解
Oct 30 Javascript
js实现按钮开关单机下拉菜单效果
Nov 22 Javascript
jQuery 实现DOM元素拖拽交换位置的实例代码
Jul 14 jQuery
jquery操作复选框checkbox的方法汇总
Feb 05 #Javascript
js中hash和ico的关联分析
Feb 05 #Javascript
js与jquery实时监听输入框值的oninput与onpropertychange方法
Feb 05 #Javascript
moment.js轻松实现获取当前日期是当年的第几周
Feb 05 #Javascript
javascript判断移动端访问设备并解析对应CSS的方法
Feb 05 #Javascript
Javascript数组操作函数总结
Feb 05 #Javascript
Javascript毫秒数用法实例
Feb 05 #Javascript
You might like
丧钟首部独立剧集《丧钟:骑士与龙》北美正式开播,场面血腥
2020/04/09 欧美动漫
php将文本文件转换csv输出的方法
2014/12/31 PHP
ThinkPHP进程计数类Process用法实例详解
2015/09/25 PHP
Laravel4中的Validator验证扩展用法详解
2016/07/26 PHP
javascript中"/"运算符常见错误
2010/10/13 Javascript
js取滚动条的尺寸的函数代码
2011/11/30 Javascript
网页源代码保护(禁止右键、复制、另存为、查看源文件)
2012/05/23 Javascript
jQuery学习笔记 操作jQuery对象 文档处理
2012/09/19 Javascript
JavaScript判断一个字符串是否包含指定子字符串的方法
2015/03/18 Javascript
jQuery实现简单滚动动画效果
2016/04/07 Javascript
JS正则表达式学习之贪婪和非贪婪模式实例总结
2016/12/26 Javascript
小程序自定义日历效果
2018/12/29 Javascript
vue实现鼠标移入移出事件代码实例
2019/03/27 Javascript
wx-charts 微信小程序图表插件的具体使用
2019/08/18 Javascript
element中table高度自适应的实现
2020/10/21 Javascript
Python函数的周期性执行实现方法
2016/08/13 Python
Django查询数据库的性能优化示例代码
2017/09/24 Python
Scrapy框架CrawlSpiders的介绍以及使用详解
2017/11/29 Python
Python内置random模块生成随机数的方法
2019/05/31 Python
完美解决keras 读取多个hdf5文件进行训练的问题
2020/07/01 Python
Python模拟键盘输入自动登录TGP
2020/11/27 Python
突袭HTML5之Javascript API扩展3—本地存储全新体验
2013/01/31 HTML / CSS
iphoneX 适配客户端H5页面的方法教程
2017/12/08 HTML / CSS
五分钟学会HTML5的WebSocket协议
2019/11/22 HTML / CSS
详解移动端h5页面根据屏幕适配的四种方案
2020/04/15 HTML / CSS
英国领先的亚洲旅游专家:Wendy Wu Tours
2018/01/21 全球购物
美国综合购物商城:UnbeatableSale.com
2018/11/28 全球购物
Crocs波兰官方商店:女鞋、男鞋、童鞋、洞洞鞋
2019/10/08 全球购物
Hotels.com韩国:海外国内旅行所需的酒店和住宿预订网站
2020/05/08 全球购物
德尔福集团DELPHI的笔试题
2012/02/22 面试题
公司司机岗位职责范本
2014/03/03 职场文书
综合实践活动总结
2014/05/05 职场文书
购房个人委托书范本
2014/10/11 职场文书
2014年社团工作总结范文
2014/11/27 职场文书
8个JS的reduce使用实例和reduce操作方式
2021/10/05 Javascript
PostgreSQL并行计算算法及参数强制并行度设置方法
2022/04/06 PostgreSQL