Skip to content

Instantly share code, notes, and snippets.

@katyo
Last active February 23, 2017 22:15
Show Gist options
  • Save katyo/4c7c469c28b5976e16ca87d89bac382a to your computer and use it in GitHub Desktop.
Save katyo/4c7c469c28b5976e16ca87d89bac382a to your computer and use it in GitHub Desktop.
Comparison of js string testing techniques
var allAttrs = ["abbr","accept","accept-charset","accesskey","action","alt","async","autocomplete","autocomplete","autofocus","autoplay","border","challenge","charset","charset","checked","cite","class","cols","colspan","content","contenteditable","controls","coords","crossorigin","data","datetime","datetime","default","defer","dir","dir","dirname","disabled","download","enctype","for","for","form","formaction","formenctype","formmethod","formnovalidate","formtarget","headers","height","hidden","high","href","href","href","hreflang","http-equiv","id","ismap","keytype","kind","label","lang","list","loop","low","manifest","max","max","maxlength","media","mediagroup","method","min","min","minlength","multiple","muted","name","name","name","name","name","name","novalidate","optimum","pattern","placeholder","poster","preload","readonly","rel","required","reversed","rows","rowspan","sandbox","spellcheck","scope","selected","shape","size","sizes","span","src","srcdoc","srclang","start","step","style","tabindex","target","target","target","title","title","title","title","title","translate","type","type","type","type","type","typemustmatch","usemap","value","value","value","value","value","value","width","wrap"];
var booleanAttrsArray = ["allowfullscreen", "async", "autofocus", "autoplay", "checked", "compact", "controls", "declare", "default", "defaultchecked", "defaultmuted", "defaultselected", "defer", "disabled", "draggable", "enabled", "formnovalidate", "hidden", "indeterminate", "inert", "ismap", "itemscope", "loop", "multiple", "muted", "nohref", "noresize", "noshade", "novalidate", "nowrap", "open", "pauseonexit", "readonly", "required", "reversed", "scoped", "seamless", "selected", "sortable", "spellcheck", "translate", "truespeed", "typemustmatch", "visible"];
var booleanAttrsHash = {
allowfullscreen: 1,
async: 1,
autofocus: 1,
autoplay: 1,
checked: 1,
compact: 1,
controls: 1,
declare: 1,
default: 1,
defaultchecked: 1,
defaultmuted: 1,
defaultselected: 1,
defer: 1,
disabled: 1,
draggable: 1,
enabled: 1,
formnovalidate: 1,
hidden: 1,
indeterminate: 1,
inert: 1,
ismap: 1,
itemscope: 1,
loop: 1,
multiple: 1,
muted: 1,
nohref: 1,
noresize: 1,
noshade: 1,
novalidate: 1,
nowrap: 1,
open: 1,
pauseonexit: 1,
readonly: 1,
required: 1,
reversed: 1,
scoped: 1,
seamless: 1,
selected: 1,
sortable: 1,
spellcheck: 1,
translate: 1,
truespeed: 1,
typemustmatch: 1,
visible: 1
};
var booleanAttrsRegex = /^(?:a(?:llowfullscreen|sync|uto(?:focus|play))|c(?:hecked|o(?:mpact|ntrols))|d(?:e(?:clare|f(?:ault(?:(?:check|(?:mu|selec)t)ed)?|er))|isabled|raggable)|enabled|formnovalidate|hidden|i(?:n(?:determinate|ert)|smap|temscope)|loop|mu(?:ltiple|ted)|no(?:href|resize|shade|validate|wrap)|open|pauseonexit|re(?:adonly|(?:quir|vers)ed)|s(?:coped|e(?:amless|lected)|ortable|pellcheck)|t(?:r(?:anslate|uespeed)|ypemustmatch)|visible)$/;
var booleanAttrsSet = new Set(booleanAttrsArray);
var n = 10e3;
function bench(t, f) {
var s = Date.now();
for (var i = 0; i < n; i++) {
f();
}
var e = Date.now() - s;
console.log(t, (n/1000) + "k", e, "mS");
}
bench("impelling", function() {
var res;
for(var i = 0; i < allAttrs.length; i++) {
res = allAttrs.indexOf(allAttrs[i]);
}
});
bench("array search", function() {
var res;
for(var i = 0; i < allAttrs.length; i++) {
res = booleanAttrsArray.indexOf(allAttrs[i]);
}
});
bench("hash lookup", function() {
var res;
for(var i = 0; i < allAttrs.length; i++) {
res = booleanAttrsHash[allAttrs[i]];
}
});
bench("regex match", function() {
var res;
for(var i = 0; i < allAttrs.length; i++) {
res = booleanAttrsRegex.test(allAttrs[i]);
}
});
bench("set lookup", function() {
var res;
for(var i = 0; i < allAttrs.length; i++) {
res = booleanAttrsSet.has(allAttrs[i]);
}
});
@YarnSphere
Copy link

This is quite interesting.
Just out of curiosity, could you add a test using Set?

@jorgebucaran
Copy link

How is a regex faster than a hash lookup? 🤔

And, what about the bundle size? Does it increase / decrease?

@katyo
Copy link
Author

katyo commented Jan 18, 2017

It may looks surprising, but testing string using regex really faster than hash(?)/array lookup. At least all mainstream JS engines, which I tested, confirm this. But real increasing of speed is differs from engine to engine. Look at my results above or you can run test code yourself.

ECMAScript Environment Speed increase comparing with hash lookup
Firefox: 45.6.0 15%
Chromium: 55.0.2883.75 56%
Node: v4.3.1 80%

Of course, the bundle size also decrease when we use regex. It's so because regex is short itself, but optimized regex is yet more short than array with strings or object with keys.

@katyo
Copy link
Author

katyo commented Jan 18, 2017

@nunocastromartins: I added test using Set too. The sets works really much faster in v8-based environments (Node, Chromium).

@mightyiam
Copy link

Finding a real use case for something less commonly used it exciting.

@katyo
Copy link
Author

katyo commented Jan 19, 2017

Finding a techniques for optimization of hot code path is exciting.

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