在HAML模板中使用:coffescript过滤器的性能影响?

时间:2013-07-10 01:08:46

标签: ruby-on-rails coffeescript haml

所以HAML 4 includes a coffeescript filter,让我们爱好咖啡的人们可以做这样的好事:

- word = "Awesome."

:coffeescript
  $ ->
    alert "No semicolons! #{word}"

我的问题:对于最终用户,这比使用等效的:javascript过滤器慢吗?使用coffeescript过滤器是否意味着coffeescript将在每次页面加载时编译为javascript(这显然会造成性能灾难),或者这只会在应用程序启动时发生一次?

2 个答案:

答案 0 :(得分:15)

取决于。

当Haml编译过滤器时,它会检查过滤器文本contains any interpolation#{...})。如果没有,那么每个请求都会转换相同的文本,因此转换在编译时完成一次,结果包含在模板中。

如果滤镜文本中有 插值,那么要转换的实际文本会因每次请求而异,因此每次都需要编译Coffeescript。

这是一个例子。首先没有插值:

:coffeescript
  $ ->
    alert "No semicolons! Awesome"

这会生成代码(使用haml -d来查看生成的Ruby代码):

_hamlout.buffer << "<script>\n  (function() {\n    $(function() {\n      return alert(\"No semicolons! Awesome\");\n    });\n  \n  }).call(this);\n</script>\n";

此代码只是在缓冲区中添加一个字符串,因此不会重新编译Coffeescript。

现在插值:

- word = "Awesome."

:coffeescript
  $ ->
    alert "No semicolons! #{word}"

这会产生:

 word = "Awesome."
_hamlout.buffer << "#{
find_and_preserve(Haml::Filters::Coffee.render_with_options(
"$ ->
  alert \"No semicolons! #{word}\"\n", _hamlout.options))
}\n";

在这里,由于Haml需要等待查看插值的值,每次都会重新编译Coffeescript。

您可以避免在:coffeescript过滤器中没有任何插值的情况下针对每个请求编译Coffeescript。

:javascript过滤器的行为类似,检查是否存在任何插值,但由于:javascript过滤器仅在运行时向缓冲区输出一些文本,因此使用的性能损失要小得多它。您可以合并:javascript:coffeescript过滤器,将插值数据放在:javascript中并保持:coffeescript静态:

- word = "Awesome"

:javascript
  var message = "No semicolons! #{word}";

:coffeescript
  alert message

答案 1 :(得分:4)

亚马的回答很清楚。我帮助从哈希中向:coffeescript过滤器添加本地化。这样您就不需要使用全局JavaScript变量。作为旁注:在Linux上,减速实际上可以忽略不计。但是在Windows上,对性能的影响非常重要(每个块编译容易超过100毫秒)。

module HamlHelper
  def coffee_with_locals locals={}, &block
    block_content = capture_haml do
      block.call
    end

    return block_content if locals.blank?

    javascript_locals = "\nvar "
    javascript_locals << locals.map{ |key, value| j(key.to_s) + ' = ' + value.to_json.gsub('</', '<\/') }.join(",\n    ")
    javascript_locals << ";\n"

    content_node = Nokogiri::HTML::DocumentFragment.parse(block_content)
    content_node.search('script').each do |script_tag|
      # This will match the '(function() {' at the start of coffeescript's compiled code
      split_coffee = script_tag.content.partition(/\(\s*function\s*\(\s*\)\s*\{/)
      script_tag.content = split_coffee[0] + split_coffee[1] +  javascript_locals + split_coffee[2]
    end

    content_node.to_s.html_safe
  end
end

它允许您执行以下操作:

= coffee_with_locals "test" => "hello ", :something => ["monde", "mundo", "world"], :signs => {:interogation => "?", :exclamation => "!"} do
  :coffeescript
    alert(test + something[2] + signs['exclamation'])

由于没有interpollat​​ion,代码实际上是正常编译的。