|
export interface Experiment<T> { |
|
label: string; |
|
use: () => T; |
|
try: () => T; |
|
predicate?: (a: T, b: T) => boolean; |
|
} |
|
|
|
function measure<T>(callback: () => T) { |
|
const start = performance.now(); |
|
const result = callback(); |
|
const end = performance.now(); |
|
const time = (end - start) |
|
return { result, time }; |
|
} |
|
|
|
const i = (x: boolean | undefined) => x === true ? '✔️' : '❌'; |
|
|
|
function logEquality(a: any, b: any, predicate?: (a: any, b: any) => boolean) { |
|
const equals = a == b; |
|
const strictEquals = a === b; |
|
const jsonEquals = JSON.stringify(a) == JSON.stringify(b); |
|
const predicateEquals = predicate != null ? predicate(a, b) : undefined; |
|
|
|
let result, label; |
|
if (predicate != null) { |
|
result = predicateEquals; |
|
label = 'predicate' |
|
} else if (typeof a === 'object') { |
|
result = jsonEquals; |
|
label = 'JSON.stringify equality' |
|
} else { |
|
result = strictEquals; |
|
label = 'strict equality' |
|
} |
|
|
|
console.groupCollapsed(i(result) + ' ' + label) |
|
if (predicateEquals != null) { |
|
console.log(i(predicateEquals), 'predicate (', a, ',', b, ')') |
|
} |
|
console.log(i(equals), a, '===', b); |
|
console.log(i(strictEquals), a, '==', b); |
|
console.log(i(jsonEquals), JSON.stringify(a), '===', JSON.stringify(b), '(via JSON.stringify)'); |
|
console.groupEnd(); |
|
} |
|
|
|
function runAndLogTimes<T>(experiment: Experiment<T>) { |
|
const { result: useResult, time: useTime } = measure(() => experiment.use()); |
|
const { result: tryResult, time: tryTime } = measure(() => experiment.try()); |
|
const diff = useTime - tryTime; |
|
const pct = (100 * diff / useTime).toFixed(0) + '%'; |
|
if (diff >= 0) { |
|
console.groupCollapsed(`✔️ ${pct} faster`) |
|
} else { |
|
console.groupCollapsed(`❌ ${pct} slower`) |
|
} |
|
console.log('use ⏱️ ' + useTime + 'ms') |
|
console.log('try ⏱️ ' + tryTime + 'ms') |
|
console.log('diff ⏱️ ' + diff + 'ms') |
|
console.groupEnd(); |
|
return { useResult, tryResult }; |
|
} |
|
|
|
export function experiment<T>(experiment: Experiment<T>): T { |
|
console.group('[Experiment] ' + experiment.label); |
|
const { useResult, tryResult } = runAndLogTimes(experiment); |
|
logEquality(tryResult, useResult, experiment.predicate) |
|
console.groupEnd(); |
|
return useResult; |
|
} |