jsPerf.app is an online JavaScript performance benchmark test runner & jsperf.com mirror. It is a complete rewrite in homage to the once excellent jsperf.com now with hopefully a more modern & maintainable codebase.
jsperf.com URLs are mirrored at the same path, e.g:
https://jsperf.com/negative-modulo/2
Can be accessed at:
https://jsperf.app/negative-modulo/2
Compare performances when evaluating expressions using the above functions
<script scr="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/sval@0.6.3/dist/sval.min.js"></script>
const TEMPLATE_OBJECT = {
defaultLabel:
"${Object.values(currentRecord?.lookupsByField)[0][0].field==='HIERARCHY-hierarchy_senior_market_head' ? 'Senior Market Head Unassigned': Object.values(currentRecord?.lookupsByField)[0][0].field==='HIERARCHY-hierarchy_market_head' ? 'Market Head Unassigned': Object.values(currentRecord?.lookupsByField)[0][0].field==='HIERARCHY-hierarchy_sr_region_head' ? 'Senior Region Head Unassigned' : Object.values(currentRecord?.lookupsByField)[0][0].field==='HIERARCHY-hierarchy_regional_head' ? 'Region Head Unassigned':'Business Head Unassigned' }",
content: "${Date.now() - currentRecord?.start}",
}
const CONTEXT = {
currentRecord: {
start: 1736953200000,
lookupsByField: {
"HIERARCHY-hierarchy_regional_head": [{
name: "William Schulz",
lookupType: "HIERARCHY-hierarchy_regional_head",
id: "HROLE/AMERICAS_GSA_GVP/OWNERSHIP",
field: "HIERARCHY-hierarchy_regional_head",
}]
}
}
}
const REGEX_FOR_SINGLE_OR_MULTIPLE_EXP_IN_STRING = /\${([^}]*)}/g;
const REGEX_FOR_SINGLE_EXP_IN_STRING = /^\${.*}$/;
function evalTemplateObject(templateObject, context){
//don't want to allow these things to be accessible while running eval
const window = undefined;
const fetch = undefined;
const document = undefined;
const setTimeout = undefined;
const setInterval = undefined;
const { currentRecord, currentUser, iteratorObject, router, parentRecord, resources, __customContext__ } = context;
if (_.isEmpty(templateObject)) {
return templateObject;
}
const recursivelyIterate = iterator => {
//base case
if (!_.isObject(iterator)) {
if (typeof iterator === 'string') {
//for exp like ${currentRecord.name}
if (REGEX_FOR_SINGLE_EXP_IN_STRING.test(iterator)) {
const parsedValue = eval(iterator.substring(2, iterator.length - 1));
return parsedValue;
}
//for exp like 'Hi ${currentRecord.name} ${currentRecord.surname}'
return iterator.replace(REGEX_FOR_SINGLE_OR_MULTIPLE_EXP_IN_STRING, (match, group) => {
const parsedValue = eval(`${group}`);
return parsedValue;
});
}
return iterator;
}
//if iterator is array
if (Array.isArray(iterator)) {
return iterator.map(value => recursivelyIterate(value));
}
//if iterator is object
return _.reduce(
iterator,
(acc, value, key) => {
acc[key] = recursivelyIterate(value);
return acc;
},
{}
);
};
try {
return recursivelyIterate(templateObject);
} catch (error) {
return templateObject;
}
};
const svalInterpreter = new Sval({
ecmaVer: 11,
sourceType: "script",
sandBox: true,
});
const ASTMapCache = new Map();
function svalParseObject(templateObject, context) {
svalInterpreter.import({
currentRecord: context.currentRecord,
currentUser: context.currentUser,
iteratorObject: context.iteratorObject,
router: context.router,
parentRecord: context.parentRecord,
resources: context.resources,
__customContext__: context.__customContext__,
});
if (_.isEmpty(templateObject)) {
return templateObject;
}
const recursivelyIterate = (iterator) => {
//base case
if (!_.isObject(iterator)) {
if (typeof iterator === "string") {
//for exp like ${currentRecord.name}
if (REGEX_FOR_SINGLE_EXP_IN_STRING.test(iterator)) {
const scriptToEvaluate = `exports.__output__ = ${iterator.substring(
2,
iterator.length - 1
)}`;
if (!ASTMapCache.has(scriptToEvaluate)) {
ASTMapCache.set(
scriptToEvaluate,
svalInterpreter.parse(scriptToEvaluate)
);
}
svalInterpreter.run(ASTMapCache.get(scriptToEvaluate));
return svalInterpreter.exports.__output__;
}
//for exp like 'Hi ${currentRecord.name} ${currentRecord.surname}'
return iterator.replace(
REGEX_FOR_SINGLE_OR_MULTIPLE_EXP_IN_STRING,
(match, group) => {
const scriptToEvaluate = `exports.__output__ = ${group}`;
if (!ASTMapCache.has(scriptToEvaluate)) {
ASTMapCache.set(
scriptToEvaluate,
svalInterpreter.parse(scriptToEvaluate)
);
}
svalInterpreter.run(ASTMapCache.get(scriptToEvaluate));
return svalInterpreter.exports.__output__;
}
);
}
return iterator;
}
//if iterator is array
if (Array.isArray(iterator)) {
return iterator.map((value) => recursivelyIterate(value));
}
//if iterator is object
return _.reduce(
iterator,
(acc, value, key) => {
acc[key] = recursivelyIterate(value);
return acc;
},
{}
);
};
try {
return recursivelyIterate(templateObject);
} catch (error) {
return templateObject;
}
}
function lodashParseObject(
templateObject,
context
){
if (_.isEmpty(templateObject)) {
return templateObject;
}
try {
return JSON.parse(_.template(JSON.stringify(templateObject))(context)) ??{};
} catch (e) {
return templateObject;
}
};
Ready to run.
Test | Ops/sec | |
---|---|---|
eval |
| ready |
sval |
| ready |
lodash/_template |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.