Go 优化html/模板组合

Go 优化html/模板组合,go,Go,我想看看是否有更好(更快、更有组织)的方法在围棋中分割我的模板。我非常喜欢使用html/模板(或其包装器),因为我信任它的安全模型 现在我使用template.ParseGlob解析init()中的所有模板文件 我将template.Funcs应用于生成的模板 我在每个模板中设置一个$title(即listing_payment.tmpl)并将其传递给内容模板 我知道html/template会在解析后将模板缓存在内存中 我的处理程序只调用t.ExecuteTemplate(w,“name.t

我想看看是否有更好(更快、更有组织)的方法在围棋中分割我的模板。我非常喜欢使用html/模板(或其包装器),因为我信任它的安全模型

  • 现在我使用
    template.ParseGlob
    解析
    init()中的所有模板文件
  • 我将template.Funcs应用于生成的模板
  • 我在每个模板中设置一个
    $title
    (即
    listing_payment.tmpl
    )并将其传递给内容模板
  • 我知道
    html/template
    会在解析后将模板缓存在内存中
  • 我的处理程序只调用
    t.ExecuteTemplate(w,“name.tmpl”,map[string]接口{})
    ,并且不对每个请求进行任何愚蠢的解析
  • 我从多个片段组成模板(我觉得这有点笨重),如下所示:

    {{ $title := "Page Title" }}
    {{ template "head" $title }}
    {{ template "checkout" }}
    {{ template "top" }}
    {{ template "sidebar_details" . }}
    {{ template "sidebar_payments" }}
    {{ template "sidebar_bottom" }}
    
    <div class="bordered-content">
      ...
          {{ template "listing_content" . }}
      ...
    </div>
    
    {{ template "footer"}}
    {{ template "bottom" }}
    
    {{$title:=“页面标题”}
    {{template“head”$title}
    {{模板“签出”}
    {{模板“顶部”}
    {{模板“侧边栏_详细信息”。}
    {{模板“边栏付款”}
    {{template“sidebar_bottom”}
    ...
    {{模板“列出内容”}
    ...
    {{模板“页脚”}
    {{模板“底部”}
    
我的三个问题是:

  • 这是性能问题,还是多个
    {{template“name”}
    标记会导致潜在的每请求性能问题?在压力测试较重的页面时,我看到很多
    写断管道
    错误。这可能只是由于套接字超时(即,在编写器可以完成之前关闭套接字),而不是某种按请求组合(否则请更正!)

  • 在html/模板包的约束范围内,有没有更好的方法来实现这一点?中的第一个示例接近我想要的。扩展基本布局,并根据需要替换标题、侧栏和内容块

  • 有些相切:当template.ExecuteTemplate在请求期间返回错误时,是否有一种惯用的方法来处理它?如果我将writer传递给一个错误处理程序,我最终会在页面上看到soup(因为它只是继续写入),但是re-direct看起来不像惯用的HTTP


  • 在Reddit的帮助下,我成功地找到了一种相当合理(且性能良好)的方法,可以:

    • 使用内容块构建布局
    • 创建有效“扩展”这些布局的模板
    • 用其他模板填充块(脚本、边栏等)
    base.tmpl

    <html>
    <head>
        {{ template "title" .}}
    </head>
    <body>
        {{ template "scripts" . }}
        {{ template "sidebar" . }}
        {{ template "content" . }}
    <footer>
        ...
    </footer>
    </body>
    
    {{ define "title"}}<title>Index Page</title>{{ end }}
    // We must define every block in the base layout.
    {{ define "scripts" }} {{ end }} 
    {{ define "sidebar" }}
        // We have a two part sidebar that changes depending on the page
        {{ template "sidebar_index" }} 
        {{ template "sidebar_base" }}
    {{ end }}
    {{ define "content" }}
        {{ template "listings_table" . }}
    {{ end }}
    

    从最初的基准测试(使用
    wrk
    )来看,当涉及到重载时,它的性能似乎要高一些,这可能是因为我们没有在每个请求中传递一个完整的
    ParseGlob
    模板。这也使模板的编写变得简单得多。

    我是个新手,正在尝试解决这个问题。
    data
    参数只是发送到模板的参数散列吗?@wuliwong因为数据是一个
    接口{}
    它可以是任何你想要的。我通常会传递一个
    map[string]接口{}
    ,其中映射键是“user”、“itemList”等。一位同事指出,
    .ExecuteTemplate
    采用与
    .Execute
    相同的方式获取参数。我的问题在别处。我正在将参数传递给嵌套模板。谢谢你的回复!如果您有用户角色,并且每个角色都有不同的内容菜单,该怎么办?为每个角色创建不同的模板[“index.html”]?好的,那么唯一的解决方案似乎是使用web组件的方法,以便在不创建新模板的情况下加载每个角色的子内容。@cespinoza要么在渲染模板时加载,要么在Go 1.6中使用新块功能-
    var templates map[string]*template.Template
    
    var ErrTemplateDoesNotExist = errors.New("The template does not exist.")
    
    // Load templates on program initialisation
    func init() {
        if templates == nil {
            templates = make(map[string]*template.Template)
        }
    
        templates["index.html"] = template.Must(template.ParseFiles("index.tmpl", "sidebar_index.tmpl", "sidebar_base.tmpl", "listings_table.tmpl", "base.tmpl"))
        ...
    }
    
    // renderTemplate is a wrapper around template.ExecuteTemplate.
    func renderTemplate(w http.ResponseWriter, name string, data map[string]interface{}) error {
        // Ensure the template exists in the map.
        tmpl, ok := templates[name]
        if !ok {
            return ErrTemplateDoesNotExist
        }
    
        w.Header().Set("Content-Type", "text/html; charset=utf-8")
        tmpl.ExecuteTemplate(w, "base", data)
    
        return nil
    }