http://blog.csdn.net/cndes/art ... 88771 这有一篇文章,说是剖析beetl模板引擎,并与同为国内的tiny模板引擎做对比(以下简称“剖析beetl”),其剖析过程公正,但结论却不正确(文中暗示的结论,而不是文章最后一段总结),
每次在百度里搜索beetl,这篇文章总会出现,也有打算使用beetl的人会将信将疑的把这文章发给我看以求证里面剖析是否正确。在beetl社区解释都比较费口舌,因此决定写一篇文章说明一下我观点。
那篇剖析文章太长,唯一上代码的地方就是beetl的 for循环实现源码,作者也拿出tiny 模板引擎的循环实现源码,来证明“tiny短小精悍,功能丰富,然而那个作者弄错了。
作者不清楚beetl的循环有一个重要功能,安全输出,代码如下(79行)
// java 实现
if (collection == null)
{
if (!this.hasSafe)
{
BeetlException ex = new BeetlException(BeetlException.NULL);
ex.pushToken(exp.token);
throw ex;
}
else
{
it = new IteratorStatus(Collections.EMPTY_LIST);
}
}
也就是说在安全模式下,如果结果集为空,则不会进入循环体,也不会抛错。虽然多了6行代码,却多了一个安全输出功能,beetl开发者只要用安全输出符号! 就可以了,如下beetl代码
//beetl 代码
var users = null;
for(u in users!){
}
再回头看看那beetl源码,如果集合为null,且没有安全输出,则会抛出一个BeetlException异常,说明是空值异常,并且 ex.pushToken(exp.token); 这个语句通过token指明了是哪个符号出错,
beetl的错误提示非常友好,这是众所周知的,也在于它的代码里处处有主动的异常的处理,而不是被动抛出异常。
然后我们再看104行代码
ctx.vars[varIndex + 1] = it; 这句代码是将集合赋值到beetl变量表里,同样还要114行的赋值 ctx.vars[varIndex] = it.next(); 这种将值赋值给数组元素的方式,类似低级语言的指针,带来的好处就是通过数组索引访问变量,速度非常快,这在我的一篇博客里说明过这个问题http://my.oschina.net/xiandafu/blog/293167,这篇博客说明,通过数组索引访问变量,比传统模板引擎使用的Map通过变量名来存取快100倍。
当然实现这个为变量分配索引(类似c语言的指针),用了大量的语法解析代码,这也是beetl本身较大的原因(然而远小于freemarker和veclotiy),那篇剖析文章显然没有看到beetl的这个特性,而草率认为beetl体积过大,“剖析beetl”也没有看到beetl 对for循环的优化,因为for循环总要对跳出语句进行检查(break;return;continue),因此,代码看起来如下(115行)
forPart.execute(ctx);
switch (ctx.gotoFlag)
{
case IGoto.NORMAL:
break;
case IGoto.CONTINUE:
ctx.gotoFlag = IGoto.NORMAL;
continue;
case IGoto.RETURN:
return;
case IGoto.BREAK:
ctx.gotoFlag = IGoto.NORMAL;
return;
}
但beetl也对于这种跳出做了优化,因为在语法解析阶段,就能分析出循环是否含有跳出语句,如果没有跳出语句,则不必执行跳出检测,代码在139行
// java实现
while (it.hasNext())
{
ctx.vars[varIndex] = it.next();
forPart.execute(ctx);
}
代码在109行先检测是否含有跳出语句if (this.hasGoto),如果没有,则直接执行如上循环
最后,让我们再来看看beetl循环另外一个特性,elsefor 语法,如果没有进入循环体,则进入eslefor循环,如下beetl代码
// beetl代码
var users = null;
for(u in users!){
}elsefor{
print("no value");
}
实现这个特性,beetl仍然用了"几句冗长代码"实现,代码如下:
// java实现
if (!it.hasData())
{
if (elseforPart != null)
elseforPart.execute(ctx);
}
}
通过it.hasData 判断是否进入循环体,如果没有,但模板具有elsefor,则执行elsefor部分逻辑。
到此为止,for循环实现的主体总共80余行代码自我剖析完毕,beetl里面有安全输出,有eslefor 特色语法,有跳出检测以优化性能,还有高性能的变量管理,还有无处不在异常处理,作为beetl作者,我并不觉得代码还能精简到什么程度,如果你反观"剖析beetl文章"里提到的tiny template的循环实现源码,你会问,安全输出在哪里?如果没有进入循环体,我是否也有elsefor帮忙处理?还有,怎么没看到异常处理.以及跳出检测和跳出优化?tiny template 的变量管理方式还是map方式而不是速度更多的数组方式?
相信你已经对“剖析beetl”这文章是否靠谱已经有了正确认识。同时市场也是检验真理的标准,我作为独立开发者(也有爱好者捐献了beetl扩展),不买粉,不拉票,不巡讲,没有企业推手,通过5年的开发和维护,beetl事实上已经成为国内最为流行的java模板引擎之一,能代替长期垄断的国外freemaker和velcoity。,这些市场成果也证明了“剖析beetl"是多么的不靠谱和结论草率!