Quellcode durchsuchen

perf(template): improve a tad the rendering of icons

On the main page (showing ~every unread feed item), every item
uses at least 4 icons. For 100 unread items, that's 400 icons, meaning
that the `icon` func is called 400 times.

On my local microbenchmark, using `fmt.Sprintf` uses one dynamic allocation and
takes ~275ns. Using concatenation in a dedicated function (that gets inlined)
doesn't allocate any memory, and takes ~2.1ns. This thus saves 400 short-lived
allocations and reduces the execution time by a factor of 100.
jvoisin vor 2 Wochen
Ursprung
Commit
f74870d796
1 geänderte Dateien mit 12 neuen und 7 gelöschten Zeilen
  1. 12 7
      internal/template/functions.go

+ 12 - 7
internal/template/functions.go

@@ -89,13 +89,7 @@ func (f *funcMap) Map() template.FuncMap {
 		},
 		"theme_color": model.ThemeColor,
 		"iconPath":    f.iconPath,
-		"icon": func(iconName string) template.HTML {
-			return template.HTML(fmt.Sprintf(
-				`<svg class="icon" aria-hidden="true"><use href="%s#icon-%s"/></svg>`,
-				f.iconPath("sprite.svg"),
-				iconName,
-			))
-		},
+		"icon":        f.iconFunc(),
 		"nonce": func() string {
 			return crypto.GenerateRandomStringHex(16)
 		},
@@ -167,6 +161,17 @@ func (f *funcMap) iconPath(filename string) string {
 	return fmt.Sprintf("%s/icon/_/%s", f.basePath, filename)
 }
 
+func (f *funcMap) iconFunc() func(string) template.HTML {
+	// Concatenation is used instead of fmt.Sprintf,
+	// as it's much faster, and this function is called
+	// a bunch of times per feed item on the main page.
+	prefix := `<svg class="icon" aria-hidden="true"><use href="` + f.iconPath("sprite.svg") + `#icon-`
+	const suffix = `"/></svg>`
+	return func(iconName string) template.HTML {
+		return template.HTML(prefix + iconName + suffix)
+	}
+}
+
 func csp(user *model.User, nonce string) string {
 	policies := map[string]string{
 		"default-src":               "'none'",