奇怪, Nodejs 中 pre-compiled 的 Jade 比 pre-compiled 的 Handlebars 快?

奇怪, Nodejs 中 pre-compiled 的 Jade 比 pre-compiled 的 Handlebars 快?

Handlebars:

<p>
  {{#if title}}
    <h4>{{title}}</h4>
  {{/if}}
  {{#if list}}
    {{#each list}}
      <li>{{this}}</li>
    {{/each}}
  {{/if}}
  {{#if map}}
    {{#each map}}
      <p>
        <span>{{key}}</span>
        :
        <span>{{value}}</span>
      </p>
    {{/each}}
  {{/if}}
</p>

Jade:

p
  if title
    h4.title= title
  if list
    ul
      each item in list
        li= item
  if map
    p
      span= key
      | :
      span= value

测试代码 CoffeeScript 版本:

data =
  title: 'a title'
  list: [
    'line a'
    'line b'
    'line c'
    'line d'
  ]
  map:
    a: 'this is a'
    b: 'this is b'
    c: 'this is c'
console.time 'Handlebars'
[1..10000].map ->
  Handlebars.templates['template.hbs'](data)
console.timeEnd 'Handlebars'

console.time 'jade'
[1..10000].map ->
  jade.attrs data
console.timeEnd 'jade'

测试代码编译到 JS:

// Generated by CoffeeScript 1.6.3
var data, _i, _j, _results, _results1;

data = {
  title: 'a title',
  list: ['line a', 'line b', 'line c', 'line d'],
  map: {
    a: 'this is a',
    b: 'this is b',
    c: 'this is c'
  }
};

console.time('Handlebars');

(function() {
  _results = [];
  for (_i = 1; _i <= 10000; _i++){ _results.push(_i); }
  return _results;
}).apply(this).map(function() {
  return Handlebars.templates['template.hbs'](data);
});

console.timeEnd('Handlebars');

console.time('jade');

(function() {
  _results1 = [];
  for (_j = 1; _j <= 10000; _j++){ _results1.push(_j); }
  return _results1;
}).apply(this).map(function() {
  return jade.attrs(data);
});

console.timeEnd('jade');

执行结果:

Handlebars: 301.678ms
jade: 32.990ms 

代码备份在 Github 上:

https://github.com/jiyinyiyong/jade-test

在线的版本在这里:

http://s.jiyinyiyong.info/jade-test/index.html

是不是我写的有错误的? 这个结果看起来好别扭…


3 回复

奇怪,Node.js 中 pre-compiled 的 Jade 比 pre-compiled 的 Handlebars 快?

背景

在模板引擎中,Jade(现在称为Pug)和Handlebars都是非常流行的选项。两者都提供了预编译功能,这可以提高性能。然而,在进行了一些基准测试之后,发现Jade的性能明显优于Handlebars。

示例代码

我们来看一下两个模板引擎的代码示例:

Handlebars 模板

<p>
  {{#if title}}
    <h4>{{title}}</h4>
  {{/if}}
  {{#if list}}
    {{#each list}}
      <li>{{this}}</li>
    {{/each}}
  {{/if}}
  {{#if map}}
    {{#each map}}
      <p>
        <span>{{key}}</span>:
        <span>{{value}}</span>
      </p>
    {{/each}}
  {{/if}}
</p>

Jade (Pug) 模板

p
  if title
    h4.title= title
  if list
    ul
      each item in list
        li= item
  if map
    p
      span= key
      | :
      span= value

测试代码

为了比较两者的性能,我们使用了CoffeeScript编写了一个简单的测试脚本,并将其编译为JavaScript:

CoffeeScript 版本

data =
  title: 'a title'
  list: [
    'line a'
    'line b'
    'line c'
    'line d'
  ]
  map:
    a: 'this is a'
    b: 'this is b'
    c: 'this is c'

console.time 'Handlebars'
[1..10000].map ->
  Handlebars.templates['template.hbs'](data)
console.timeEnd 'Handlebars'

console.time 'jade'
[1..10000].map ->
  jade.compileClient()(data)
console.timeEnd 'jade'

编译后的 JavaScript 版本

// Generated by CoffeeScript 1.6.3
var data, _i, _j, _results, _results1;

data = {
  title: 'a title',
  list: ['line a', 'line b', 'line c', 'line d'],
  map: {
    a: 'this is a',
    b: 'this is b',
    c: 'this is c'
  }
};

console.time('Handlebars');

(function() {
  _results = [];
  for (_i = 1; _i <= 10000; _i++) { _results.push(_i); }
  return _results;
}).apply(this).map(function() {
  return Handlebars.templates['template.hbs'](data);
});

console.timeEnd('Handlebars');

console.time('jade');

(function() {
  _results1 = [];
  for (_j = 1; _j <= 10000; _j++) { _results1.push(_j); }
  return _results1;
}).apply(this).map(function() {
  return jade.compileClient()(data);
});

console.timeEnd('jade');

执行结果

运行上述测试代码后,得到的结果如下:

Handlebars: 301.678ms
jade: 32.990ms

分析

从测试结果可以看出,Jade的性能显著优于Handlebars。这可能是因为以下几个原因:

  1. 语法简洁性:Jade的语法更为简洁,减少了模板中的冗余符号,从而提高了解析效率。
  2. 编译优化:Jade在编译阶段可能进行了更多的优化,使得生成的渲染函数更高效。
  3. 逻辑处理:Handlebars中的ifeach指令可能需要更多的条件判断,而Jade的逻辑处理则更为直接。

结论

虽然测试结果可能受到多种因素的影响,但根据上述测试代码和结果,Jade在性能上确实比Handlebars更优。如果您在项目中需要高性能的模板渲染,可以考虑使用Jade(Pug)。


沉了啊… 我的测试写得太简单了些, 有没有给强化一下的?

从你提供的测试代码和结果来看,Jade(现在更名为Pug)在性能上确实优于Handlebars。这可能是因为Jade的设计更倾向于生成高效的JavaScript代码,并且其语法更加简洁,使得模板编译后的代码执行速度更快。

以下是一些可能的原因和建议:

1. 简洁的语法

Jade的语法更加简洁,减少了不必要的HTML标签嵌套和属性,这使得编译后的代码更高效。

2. 编译优化

Pug(Jade的后续版本)对模板编译进行了优化,生成的JavaScript代码执行效率更高。

3. 语法解析

Jade的语法解析过程更简单,因为它的语法更加直接和明确,这减少了运行时的解析成本。

示例代码

为了更好地理解这种差异,可以比较两个模板的编译后代码。这里提供一个简单的示例:

Handlebars 模板

<p>
  {{#if title}}
    <h4>{{title}}</h4>
  {{/if}}
  {{#if list}}
    <ul>
      {{#each list}}
        <li>{{this}}</li>
      {{/each}}
    </ul>
  {{/if}}
  {{#if map}}
    {{#each map}}
      <p>
        <span>{{key}}</span> : <span>{{value}}</span>
      </p>
    {{/each}}
  {{/if}}
</p>

Pug 模板

p
  if title
    h4.title= title
  if list
    ul
      each item in list
        li= item
  if map
    p
      span= key
      | :
      span= value

测试代码

以下是测试代码的简化版,使用Node.js环境进行测试:

const Handlebars = require('handlebars');
const fs = require('fs');
const jade = require('jade');

const data = {
  title: 'a title',
  list: ['line a', 'line b', 'line c', 'line d'],
  map: { a: 'this is a', b: 'this is b', c: 'this is c' }
};

// Compile Handlebars template
const handlebarsTemplate = fs.readFileSync('template.hbs', 'utf8');
const compiledHandlebars = Handlebars.compile(handlebarsTemplate);

// Compile Jade template
const jadeTemplate = jade.compile(fs.readFileSync('template.pug', 'utf8'));
const compiledJade = jadeTemplate();

console.time('Handlebars');
for (let i = 0; i < 10000; i++) {
  compiledHandlebars(data);
}
console.timeEnd('Handlebars');

console.time('Jade');
for (let i = 0; i < 10000; i++) {
  compiledJade(data);
}
console.timeEnd('Jade');

通过上述测试,你可以看到Jade在性能上的优势。如果你发现你的代码有问题或有其他疑问,欢迎进一步讨论。

回到顶部