---
slug: fastest-js-html-escape
title: "Fastest JavaScript HTML Escape"
date: "2022-03-09T21:42:57-04:00"
---
What is the fastest [JavaScript][js] [HTML][] escape implementation? To
find out, I:
1. Wrote [10 different JavaScript HTML escape implementations][impls].
2. Created a web-based benchmarking tool which uses [web workers][] and
the [Performance API][] to test with a variety of string sizes and
generates a downloadable [CSV][] of results.
3. Created a set of scripts to aggregate and plot the results as
[SVGs][svg].
## Results
The times are from 64-bit [Chrome 99][chrome] running in [Debian][] on a
[Lenovo Thinkpad X1 Carbon (9th Gen)][laptop]; the specific timing
results may vary for your system, but the relative results should be
comparable.
The first chart shows implementations' mean call time (95% [CI][]) as
the string length varies:
{{< figure
src="/files/posts/fastest-js-html-escape/sizes.svg"
class=image
caption="String Size vs. HTML Escape Function Call Time (μs)"
>}}
The second chart comparse implementations' mean call time (95% [CI][])
for 3000 character strings:
{{< figure
src="/files/posts/fastest-js-html-escape/times.svg"
class=image
caption="HTML Escape Function Call Times"
>}}
The red, blue, and green bars in this chart indicate the slow, medium,
and fast functions, respectively.
### Slow Functions
Anything that uses a capturing [regular expression][re].
#### Example: h2
```js
const h2 = (() => {
// characters to match
const M = /([&<>'"])/g;
// map of char to entity
const E = {
'&': '&',
'<': '<',
'>': '>',
"'": ''',
'"': '"',
};
// build and return escape function
return (v) => v.replace(M, (_, c) => E[c]);
})();
```
The capture is definitely at fault, because the call times for identical
non-capturing implementations (example: `h4`) are comparable to
everything else.
### Medium Functions
Except for the capturing [regular expression][re] implementations in the
previous section, the remaining implementations' call times were comparable
with one another. This includes:
* Reducing an array of string literals and calling `replace()`.
* Several variants of reducing an array of non-capturing [regular
expression][re] with `replace()`.
#### Example: h4
```js
const h4 = (() => {
// characters to match
const M = /[&<>'"]/g;
// map of char to entity
const E = {
'&': '&',
'<': '<',
'>': '>',
"'": ''',
'"': '"',
};
// build and return escape function
return (v) => v.replace(M, (c) => E[c]);
})();
```
### Fast Functions
Three implementations are slightly faster than the others. They all use
`replaceAll()` and match on string literals. Their call times are
indistinguishable from one another:
* h7: Reduce, Replace All
* h8: Reduce, Replace All, Frozen
* h9: Replace All Literal
#### Example: h7
```js
const h7 = (() => {
const E = [
['&', '&'],
['<', '<'],
['>', '>'],
["'", '''],
['"', '"'],
];
return (v) => E.reduce((r, e) => r.replaceAll(e[0], e[1]), v);
})();
```
## The Winner: h9
Even though the call times for `h7`, `h8`, and `h9` are
indistinguishable, I actually prefer `h9` because:
* The most legible. It is the easiest implementation to read for
beginning developers and developers who are uncomfortable with
functional programming.
* The simplist parse (probably).
* Slightly easier for browsers to optimize (probably).
Here it is:
```js
// html escape (replaceall explicit)
const h9 = (v) => {
return v.replaceAll('&', '&')
.replaceAll('<', '<')
.replaceAll('>', '>')
.replaceAll("'", ''')
.replaceAll('"', '"');
};
```
## Notes
* The benchmarking interface, aggregation and plotting scripts, and
additional information are available in the [companion GitHub
repository][repo].
* I also wrote a [DOM][]/`textContent` implementation, but I couldn't
compare it with the other implementations because [web workers][]
don't have [DOM][] access. I would be surprised if it was as fast as
the fast functions above.
* `Object.freeze()` doesn't appear to help, at least not in
[Chrome][].
**Update (2022-03-11):** I posted the benchmarking tool online at the
following URL: [https://pmdn.org/fastest-js-html-escape/][site].
[repo]: https://github.com/pablotron/fastest-js-html-escape
"Fastest JavaScript HTML Escape"
[js]: https://en.wikipedia.org/wiki/ECMAScript
"JavaScript programming language."
[html]: https://en.wikipedia.org/wiki/HTML
"HyperText Markup Language"
[impls]: https://github.com/pablotron/fastest-js-html-escape/blob/main/public/common.js
"Variety of JavaScript HTML escape implementations."
[web workers]: https://en.wikipedia.org/wiki/Web_worker
"JavaScript that runs in a background thread and communicates via messages with HTML page."
[performance api]: https://developer.mozilla.org/en-US/docs/Web/API/Performance
"Web performance measurement API."
[csv]: https://en.wikipedia.org/wiki/Comma-separated_values
"Comma-Separated Value file."
[chrome]: https://www.google.com/chrome/
"Google Chrome web browser."
[debian]: https://debian.org/
"Debian Linux distribution."
[laptop]: https://en.wikipedia.org/wiki/ThinkPad_X1_series#X1_Carbon_(9th_Gen)
"Lenovo Thinkpad X1 Carbon (9th Gen)"
[re]: https://en.wikipedia.org/wiki/Regular_expression
"Regular expression."
[ci]: https://en.wikipedia.org/wiki/Confidence_interval
"Confidence interval."
[dom]: https://en.wikipedia.org/wiki/Document_Object_Model
"Document Object Model"
[svg]: https://en.wikipedia.org/wiki/Scalable_Vector_Graphics
"Scalable Vector Graphics"
[site]: https://pmdn.org/fastest-js-html-escape/
"JavaScript HTML Escape benchmark tool."