JavaScript profiling tool and library of profiling modules and benchmarks.
JS-Profiler allows you to compare different techniques, operators and functions regarding execution speed and memory consumption. It reports results either in text or JSON format.
JS-Profiler powers https://js-profiler.com.
- Installation
- Updates
- Usage
- Profiles
- array concatenation
- array copying
- comparison operators
- (de-)composition
- guards
- loops
- map access
- map creation
- object iteration
- recursion
- Documentation
- Changelog
- License
npm i [-gS] js-profiler
v2.5.0: New profile: (de-)composition.
v2.3.0: A new contributor and a new profile: shallow array copying.
We are happy to welcome Josh Howe as a contributor to JS-Profiler! He added a new profile comparing ways to shallow copy arrays.
Big thank you and shout out to Josh Howe!
Due to updated dependencies, JS-Profiler now requires a minimum Node.js version of 10.12.0.
v2.2.0: Migrate to Node.js Performance Hooks
As of version 2.2.0 js-profiler gathers function timing information via the Performance Hooks API instead of process.hrtime().
profile.testsis renamed toprofile.functionsfunction.description(formerlytest.description) now contains a nice human readable description.function.codeSamplenow contains a short pseudo-code sample of the function under test.- use
function.codeto access the full source code of the function under test. function.keywordscontains keywords associated with the function under test.profile.keywordscontains keywords associated with this profile.
// v1 { "name" : "recursion", "description" : "Recursion variations: Calculating sum of array of integers. Profile contains a simple for-loop for reference.", "tests" : [ { "description" : "for loop sum for reference", "time" : { "average" : "1.4923μs", "minimum" : "1.0970μs", "maximum" : "38.8230μs" } }, { "description" : "recursive sum", "time" : { "average" : "1080.3024μs", "minimum" : "703.3320μs", "maximum" : "10215.1650μs" } }, { "description" : "tail recursive sum", "time" : { "average" : "1041.0375μs", "minimum" : "704.2790μs", "maximum" : "16476.7110μs" } } ], "fastest" : [ { "description" : "for loop sum for reference", "time" : { "average" : "1.4923μs", "minimum" : "1.0970μs", "maximum" : "38.8230μs" } } ] }// v2 { "name": "recursion", "description": "Recursion.", "keywords": [ "for", "loop", "recursion", "sum", "tail", "tailrecursion" ], "functions": [ { "description": "for loop sum for reference", "keywords": [ "for", "loop", "sum" ], "codeSample": "for (...) { sum += d[i] }", "code": "(d) => {\n let sum = 0;\n for (let i = 0; i < d.length; i++) {\n sum += d[i];\n }\n\n return sum;\n }", "time": { "average": "3.8774µs" } }, { "description": "recursive sum", "keywords": [ "recursion", "sum" ], "codeSample": "const f = (d) => (d && d.length && (d[0] + f(d.slice(1)))) || 0", "code": "(d) => (d && d.length && (d[0] + recursiveSum.f(d.slice(1)))) || 0", "time": { "average": "733.7537µs" } }, { "description": "tail recursive sum", "keywords": [ "recursion", "sum", "tail", "tailrecursion" ], "codeSample": "const f = (d, i = 0) => (!d.length && i) || f(d.slice(1), i + d[0])", "code": "(d, i = 0) => (!d.length && i)\n || tailRecursiveSum.f(d.slice(1), i + d[0])", "time": { "average": "769.7328µs" } } ], "fastest": [ { "description": "for loop sum for reference", "keywords": [ "for", "loop", "sum" ], "codeSample": "for (...) { sum += d[i] }", "code": "(d) => {\n let sum = 0;\n for (let i = 0; i < d.length; i++) {\n sum += d[i];\n }\n\n return sum;\n }", "time": { "average": "3.8774µs" } } ] }If installed with the -g flag you can simply run js-profiler from your command line:
For further information please refer to the CLI documentation and the man page.
// 1. Import the library const jsProfiler = require('js-profiler'); // 2. Run the profiler jsProfiler.run() .then((report) => { console.log(JSON.stringify(report, null, 2)); });For configuration options please refer to the Library documentation.
Array concatenation variations: Combining two arrays using different techniques.
Profiled operations:
a.concat(b)for (...) { a.push(b[i])}for (...) { b.unshift(a[i])}a.push.apply(a, b)Array.prototype.unshift.apply(b, a)b.reduce((arr, item) => arr.push(item), a)a.reduceRight((arr, item) => arr.unshift(item), b)[...a, ...b]
Array copying variations: creating a new array with the same elements as an existing array.
Profiled operations:
a.slice()[...a]Array.from(a)new Array(...a)a.concat([])[].concat(a)Array.prototype.unshift.apply([], a)Array.prototype.unshift.apply(new Arrray(), a)[].push(...a)(new Array()).push(...a)b = []; for(...){ b.push(a[i]) }b = new Array(); for(...){ b.push(a[i]) }b = new Array(a.length); for(...){ b[i] = a[i] }
(De-)Composition: composing objects, arrays and variables from each other.
Profiled operations:
const { a, b } = objconst { a = i } = objconst [a, b] = arrconst [a = i, b] = dconst [a, b, ...tail] = dconst a = arr[i]const a = arr[i] || jconst a = obj.bconst a = obj.b || iconst [a, b] = [b, a]const c = b; b = a; a = c
Variable comparison operators.
Profiled operations:
a > ba >= ba < ba <= b=====!=!==&&- ||
Variable guards: checking whether a variable is defined or of a certain type.
Profiled operations:
typeof !== 'undefined'typeof != 'undefined'typeof === 'function'typeof == 'function'typeof === 'number'typeof == 'number'typeof === 'object'typeof == 'object'typeof === 'string'typeof == 'string'Array.isArray!!var!varisNaN(var)Number.isNaN(var)!isNaN(var)!Number.IsNaN(var)prop in objobj.hasOwnProperty(prop)Object.prototype.hasOwnProperty.call(obj, prop)
Loop variations: Converting an array of integers into an array of booleans satisfying a conjunction of two simple relational operations.
Profiled operations:
[].forEach() => []for(i++, i < d.length) => []for(i++, i < len) => []while(i--) => [][].map() => []while(i < d.length) => []while(i < len) => []do { } while (i < d.length)do { } while (i < len)for (prop of [])
Object literal vs. Map: retrieving values.
Profiled operations:
Map.get(){}.prop
Object literal vs. Map: creating a map.
Profiled operations:
Map.set()new Map([props]){}.prop = valObject.defineProperty({}, prop, desc)Object.defineProperties({}, props){ ...props }
Object iteration: different ways of iterating over properties of an object and concatenating property names into a single string.
Profiled operations:
for (const prop in obj) {}Object.keys(obj).forEach()Object.entries(obj).forEach()for (prop of Map.keys())for (prop of Object.keys(obj))for (prop of Object.keys(obj) { obj.hasOwnProperty(prop) && ... })for (prop of Object.getOwnPropertyNames(obj))Object.getOwnPropertyNames(obj).forEach()
Recurstion variations: Calculating sum of array of integers. Profile contains a simple for-loop for reference.
Profiled operations:
for loop sum for referencerecursive sumtail recursive sum


