Skip to content

haensl/js-profiler

Repository files navigation

https://js-profiler.com

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.

NPM

CircleCI

Table of contents

Installation

npm i [-gS] js-profiler

Updates

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.

As of version 2.2.0 js-profiler gathers function timing information via the Performance Hooks API instead of process.hrtime().

New in version 2 & Migration from v1.x.y to v2.x.y

  • profile.tests is renamed to profile.functions
  • function.description (formerly test.description) now contains a nice human readable description.
  • function.codeSample now contains a short pseudo-code sample of the function under test.
  • use function.code to access the full source code of the function under test.
  • function.keywords contains keywords associated with the function under test.
  • profile.keywords contains keywords associated with this profile.

Comparison of a v1 vs. v2 profile object

Version 1.x.y profile object
// 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" } } ] }
Version 2.x.y profile object
// 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" } } ] }

Usage

CLI

If installed with the -g flag you can simply run js-profiler from your command line:

Intro

For further information please refer to the CLI documentation and the man page.

Library

// 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.

Available performance profiles:

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 } = obj
  • const { a = i } = obj
  • const [a, b] = arr
  • const [a = i, b] = d
  • const [a, b, ...tail] = d
  • const a = arr[i]
  • const a = arr[i] || j
  • const a = obj.b
  • const a = obj.b || i
  • const [a, b] = [b, a]
  • const c = b; b = a; a = c

Variable comparison operators.

Profiled operations:

  • a > b
  • a >= b
  • a < b
  • a <= 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
  • !var
  • isNaN(var)
  • Number.isNaN(var)
  • !isNaN(var)
  • !Number.IsNaN(var)
  • prop in obj
  • obj.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 = val
  • Object.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 reference
  • recursive sum
  • tail recursive sum

Sponsor this project

 

Packages

No packages published

Contributors 2

  •  
  •