标签:
Crox是一个由JavaScript语言实现的高性能跨语言模板引擎.Crox模板可以直接在JavaScript环境中使用,也可以翻译成PHP,JSP等其他编程语言的可执行方法或翻译成Velocity,Smarty等其他模板引擎的源模板,Crox将保证翻译后的结果具备最佳执行效率.
在生产系统中,我们使用的各种前后端模板引擎多有其独到的一面,而Crox的特点即它是面向"跨语言并高性能"这个目标设计的,Crox的设计过程是在模板提供的功能和模板支持的目标业务类型间进行一次独到的权衡和取舍并最终确认模板API的过程.
在实现层面,Crox是众多基于语法分析的编译型模板引擎之一.通过严格的API设计,保障翻译后各类代码逻辑简单明确,进而确保多语言环境下的高性能.而Crox语法在一定条件下为Kissy XTemplate或Crox+(开发中)等功能更加强大的前端模板引擎语法所包含,这使得面对更复杂的但仅限于纯前端的应用场景时,Crox的API得到一致的延续和加强.
随着无线业务的全面铺开,展现端研发进入全端时代,一项业务常常需要同时支持PC和移动浏览器以及IOS和Android等Native开发框架,展现端多样化促成了服务端接口向纯数据化方向发展.
就Web前端而言,无论PC端还是移动端,基于后端纯数据接口在网页端渲染HTML结构的情况越来越多(典型的是各种基于单页应用技术的WebApp),而传统的后端渲染HTML的架构依然长期存在.
我们期望寻找或构建一种高效的模板系统,可以统一的描述HTML结构生成的逻辑,让其无论在前端还是在后端采用哪种技术都有一致的输出.这样不同前端架构下的页面组件区块可以相互共享复用,也可以顺手解决掉单页应用内容无法被搜索引擎索引的问题.
综合前面的分析,我们需要一种能在多种架构快速应用的同时支持前后端渲染的模板方案.也就是说我们需要一种高性能跨语言模板引擎,我们将其定名为Crox.
实现Crox的跨语言特性需要做离线翻译器而非运行时的中间层,这样源模板通过翻译后将生成一个基于原生JavaScript,Php语言的函数.通过逻辑"直译",生成的函数具备良好的可读性,保障了执行性能,下面是一个例子:
JSON数据:
{
"name": "Chris",
"value": 10000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
}
Crox模板:
你好 {{root.name}}
你刚赢了 ¥{{ root.value}}
{{#if root.in_ca}}
嗯,税后 ¥{{ root.taxed_value}}
{{/if}}
翻译后的JavaScript函数:
function (root) {
// 忽略$htmlEncode源码
var $s = ‘‘;
$s += "你好 ";
$s += $htmlEncode(root.name);
$s += " \n你刚赢了 ¥";
$s += $htmlEncode(root.value);
$s += "\n";
if (root.in_ca) {
$s += "\n 嗯,税后 ¥";
$s += $htmlEncode(root.taxed_value);
$s += "\n";
}
return $s;
}
翻译后的Php文件内容:
你好 <?php echo crox_encode($crox_root->name);?>
你刚赢了 ¥<?php echo crox_encode($crox_root->value);?>
<?php if($crox_root->in_ca){?>
嗯,税后 ¥<?php echo crox_encode($crox_root->taxed_value);?>
<?php }?>
可以看出无论是翻译成JavaScript还是Php,翻译后代码的样子和大家读模板时直观的印象一致,遇到判断就是一个判断,遇到一个循环就是一个循环,每次输出什么数据十分明确,和徒手写出的代码一样.也正是这样的"直译"让我们明确每一行代码的性能消耗都是充分和必要的.
XTemplate翻译后的JavaScript函数:
function(scope,S,undefined) {
var buffer = "", config = this.config, engine = this, moduleWrap, utils = config.utils;
if( typeof module !== "undefined" && module.kissy) {
moduleWrap = module;
}
var runBlockCommandUtil = utils.runBlockCommand;
var getExpressionUtil = utils.getExpression;
var getPropertyOrRunCommandUtil = utils.getPropertyOrRunCommand;
buffer += ‘你好 ‘;
var id0 = getPropertyOrRunCommandUtil(engine, scope, {}, "root.name", 0, 1, undefined, false);
buffer += getExpressionUtil(id0, true);
buffer += ‘\n你刚赢了 ¥‘;
var id1 = getPropertyOrRunCommandUtil(engine, scope, {}, "root.value", 0, 2, undefined, false);
buffer += getExpressionUtil(id1, true);
buffer += ‘\n‘;
var config2 = {};
var params3 = [];
var id4 = getPropertyOrRunCommandUtil(engine, scope, {}, "root.in_ca", 0, 3, undefined, true);
params3.push(id4);
config2.params = params3;
config2.fn = function(scope) {
var buffer = "";
buffer += ‘\n 嗯,税后 ¥‘;
var id5 = getPropertyOrRunCommandUtil(engine, scope, {}, "root.taxed_value", 0, 4, undefined, false);
buffer += getExpressionUtil(id5, true);
buffer += ‘\n‘;
return buffer;
};
buffer += runBlockCommandUtil(engine, scope, config2, "if", 3);
return buffer;
}
上面是Kissy的XTemplate同样的逻辑编译后的函数,其实代码不仅仅这么多,还有很多外部的方法依赖.原因是XTemplate兼容 Mustache,兼容Handlebars提供了非常多的辅助功能.这样的翻译结果在前端,每个用户的浏览器中去运行,其消耗完全可以忽略,但一旦转移到动辄数千QPS(Query Per Second)的后端,就立刻变得不容忽视.
所以只有"直译"才能保证跨语言的高性能,如果想做到"直译",必要的功能取舍是设计的重中之重.
前端模板引擎的实现方案一般分两类,通过正则匹配或者通过语法分析,Crox因为需要进行多语言翻译,所以需要采用基于语法分析的方案.同时各种语言之间有着不小的差异,Crox需要做到逻辑简单且明确,这样在做翻译时才能避免太多不确定性引入的性能消耗.所以相比其他模板引擎Crox需要多做一些功能取舍.我们用接下来的例子,来说明CroxAPI设计思路:
JSON数据:
{
string : "a",
list : [
{},
{string : "b"}
]
}
Mustache模板:
{{#list}}{{string}} {{/list}}
在Mustache模板的循环中会查找当前item中的string值,如果没有则继续向外层数据对象中查找,最终输出"a b ".但这样的向外查找逻辑势必会引入很多代码的代价来完成,最终积少成多成为性能问题.Crox通过明确指定访问数据的位置,来避免这些消耗
Crox模板:
{{#each root.list ‘val‘}}{{root.string}} {{val.string}} {{/each}}
上面模板的输出是"a undefined b a ",即需要访问最外层的string值时使用{{root.string}},需要访问item中的string,用临时变量val来访问 {{val.string}},输出内容在数据中的位置是非常明确的.基于类似的原因XTemplate中通过"../"来访问相对层次中的数据也是不被支持的.
下面就将介绍经过反复权衡得出的Crox基础API设计基准原则.
虽然Crox支持了大量常见的模板功能,但Crox并不能覆盖XTemplate,Handlebars,EJS等众多前端模板引擎所涵盖的所有功能.我们这样看待这个问题:
综合以上的考量,Crox模板最适合处理交互不太复杂的页面展示型区块的HTML构建,可以保障在前后端渲染都能拿到良好的性能.
在最新版本的XTemplate已经包含Crox的全部语法,经常使用XTemplate的亲,欢迎熟悉下Crox的几个约定之后试试Crox吧.
规划中的Crox+是一个类似EJS语法的全功能前端模板引擎,在模板中负责逻辑的部分可以写任意复杂的JS代码.Crox+的另一个特点是无需经过语法分析解析执行,而是依赖较简单的正则匹配完成模板解析任务.
当前Crox的语法是类似Mustache风格的,为了省去语法分析环节,Crox+的语法风格将发生变化,当然Crox是可以方便的把Crox模板翻译成Crox+指定风格的模板的.
Crox是一个跨语言的高性能的模板引擎,保证性能的诀窍是保证在各种语言中模板逻辑都能"直译",为了完成这个目标,Crox对模板语法进行了较严格的约定.
使用Crox可以让页面区块生成逻辑,在前后端各种架构的产品中保持一致并运用自如,这样你开发的组件就可以做更加通用的积累和分享.
Crox语法已经被XTemplate兼容,如果你很熟悉XTemplate,简单的改变几处编码习惯,就可以享有Crox带来的便利.而当你觉得Crox力有不逮时,XTemplate会继续帮助你完成你想要的.
标签:
原文地址:http://www.cnblogs.com/gcg0036/p/4307186.html