Skip to content

Instantly share code, notes, and snippets.

@intrnl
Last active July 24, 2022 06:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save intrnl/07816a7669d0ad4620390bd69e59b9d4 to your computer and use it in GitHub Desktop.
Save intrnl/07816a7669d0ad4620390bd69e59b9d4 to your computer and use it in GitHub Desktop.
HTML escape function #bench
import { run, bench, group } from 'https://esm.sh/mitata';
function escape (value) {
const str = '' + value;
const res = str.replace(/[&<]/g, (char) => '&#' + char.charCodeAt(0) + ';');
return res;
}
const ATTR_REGEX = /[&"]/g;
const TEXT_REGEX = /[&<]/g;
function escape_new (value, is_attr = false) {
const str = '' + value;
const pattern = is_attr ? ATTR_REGEX : TEXT_REGEX;
pattern.lastIndex = 0;
let escaped = '';
let last = 0;
while (pattern.exec(str)) {
const idx = pattern.lastIndex - 1;
escaped += str.substring(last, idx) + ('&#' + str.charCodeAt(idx) + ';');
last = idx + 1;
}
return escaped + str.substring(last);
}
function escape_no_re (value, is_attr = false) {
const str = '' + value;
let escaped = '';
let last = 0;
for (let idx = 0, len = str.length; idx < len; idx++) {
const char = str.charCodeAt(idx);
if (char === 38 || char === (is_attr ? 34 : 60)) {
escaped += str.substring(last, idx) + ('&#' + char + ';');
last = idx + 1;
}
}
if (last === 0) {
return str;
}
return escaped + str.substring(last);
}
group('no escaping - long', () => {
bench('escape', () => {
escape('a quick brown fox jumps over the lazy dog', false);
});
bench('escape_new', () => {
escape_new('a quick brown fox jumps over the lazy dog', false);
});
bench('escape_no_re', () => {
escape_no_re('a quick brown fox jumps over the lazy dog', false);
});
});
group('no escaping - short', () => {
bench('escape', () => {
escape('brown fox', false);
});
bench('escape_new', () => {
escape_new('brown fox', false);
});
bench('escape_no_re', () => {
escape_no_re('brown fox', false);
});
});
group('need escaping - long', () => {
bench('escape', () => {
escape('a quick brown fox fooo<=bar&baz; jumps over the lazy dog', false);
});
bench('escape_new', () => {
escape_new('a quick brown fox fooo<=bar&baz; jumps over the lazy dog', false);
});
bench('escape_no_re', () => {
escape_no_re('a quick brown fox fooo<=bar&baz; jumps over the lazy dog', false);
});
});
group('need escaping - short', () => {
bench('escape', () => {
escape('brown < fox', false);
});
bench('escape_new', () => {
escape_new('brown < fox', false);
});
bench('escape_no_re', () => {
escape_no_re('brown < fox', false);
});
});
await run();
@intrnl
Copy link
Author

intrnl commented Jul 24, 2022

$ deno run --allow-all bench.mjs 
cpu: AMD Ryzen 7 5700U with Radeon Graphics
runtime: deno 1.24.0 (x86_64-unknown-linux-gnu)

benchmark         time (avg)             (min … max)       p75       p99      p995
---------------------------------------------------- -----------------------------
• no escaping - long
---------------------------------------------------- -----------------------------
escape        161.02 ns/iter (141.62 ns … 256.82 ns) 165.25 ns 207.96 ns 233.02 ns
escape_new     44.25 ns/iter  (41.45 ns … 166.84 ns)  44.83 ns  58.13 ns  60.48 ns
escape_no_re   79.03 ns/iter  (75.78 ns … 157.24 ns)   79.8 ns  84.41 ns  87.32 ns

summary for no escaping - long
  escape_new
   1.79x faster than escape_no_re
   3.64x faster than escape

• no escaping - short
---------------------------------------------------- -----------------------------
escape        149.98 ns/iter  (134.3 ns … 264.44 ns)  153.8 ns 186.48 ns 203.16 ns
escape_new     26.62 ns/iter   (24.89 ns … 62.74 ns)  26.84 ns  31.62 ns  51.68 ns
escape_no_re   20.45 ns/iter   (19.22 ns … 44.25 ns)  20.45 ns  25.45 ns  26.87 ns

summary for no escaping - short
  escape_no_re
   1.3x faster than escape_new
   7.34x faster than escape

• need escaping - long
---------------------------------------------------- -----------------------------
escape         504.2 ns/iter (485.03 ns … 631.87 ns)  511.2 ns 537.15 ns 631.87 ns
escape_new    240.48 ns/iter (221.54 ns … 361.76 ns) 246.65 ns 286.54 ns 287.93 ns
escape_no_re  244.61 ns/iter (226.29 ns … 330.11 ns) 247.15 ns 274.47 ns 327.93 ns

summary for need escaping - long
  escape_new
   1.02x faster than escape_no_re
   2.1x faster than escape

• need escaping - short
---------------------------------------------------- -----------------------------
escape        380.12 ns/iter (364.16 ns … 445.11 ns) 383.83 ns 431.23 ns 445.11 ns
escape_new    144.16 ns/iter  (127.26 ns … 203.8 ns) 148.52 ns 185.03 ns 202.57 ns
escape_no_re   93.01 ns/iter  (80.31 ns … 240.78 ns)   99.3 ns 124.36 ns 149.83 ns

summary for need escaping - short
  escape_no_re
   1.55x faster than escape_new
   4.09x faster than escape

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment