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
function cspSafeGetterFn(key0, key1, key2, key3, key4) {
return function(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
promise;
if (!pathVal) return pathVal;
pathVal = pathVal[key0];
if (pathVal && pathVal.then) {
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key1 || !pathVal) return pathVal;
pathVal = pathVal[key1];
if (pathVal && pathVal.then) {
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key2 || !pathVal) return pathVal;
pathVal = pathVal[key2];
if (pathVal && pathVal.then) {
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key3 || !pathVal) return pathVal;
pathVal = pathVal[key3];
if (pathVal && pathVal.then) {
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key4 || !pathVal) return pathVal;
pathVal = pathVal[key4];
if (pathVal && pathVal.then) {
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
return pathVal;
};
};
function getterFn(path, csp) {
var pathKeys = path.split('.'),
pathKeysLength = pathKeys.length,
fn;
if (csp) {
if (csp === 2) {
fn = (pathKeysLength < 6)
? cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4])
: function(scope, locals) {
var i = 0, val;
do {
val = cspSafeGetterFn(
pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++]
)(scope, locals);
locals = undefined; // clear after first iteration
} while (i < pathKeysLength);
};
} else {
fn = function(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(pathKeys[0])) ? locals : scope,
promise, i, ii, key;
for(i = 0, ii = pathKeys.length; i < ii; i++) {
if (!pathVal) break;
key = pathKeys[i];
pathVal = pathVal[key];
if (pathVal && pathVal.then) {
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
}
return pathVal;
}
}
} else {
var code = 'var l, fn, p;\n';
forEach(pathKeys, function(key, index) {
code += 'if(!s) return s;\n' +
'l=s;\n' +
's='+ (index
// we simply dereference 's' on any .dot notation
? 's'
// but if we are first then we check locals first, and if so read it first
: '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
'if (s && s.then) {\n' +
' if (!("$$v" in s)) {\n' +
' p=s;\n' +
' p.$$v = undefined;\n' +
' p.then(function(v) {p.$$v=v;});\n' +
'}\n' +
' s=s.$$v\n' +
'}\n';
});
code += 'return s;';
fn = Function('s', 'k', code); // s=scope, k=locals
fn.toString = function() { return code; };
}
return fn;
}
//////////////////////////
// Updated code
//////////////////////////
function cspSafeGetterFn2(key0, key1, key2, key3, key4, fullExp, options) {
ensureSafeMemberName(key0, fullExp);
ensureSafeMemberName(key1, fullExp);
ensureSafeMemberName(key2, fullExp);
ensureSafeMemberName(key3, fullExp);
ensureSafeMemberName(key4, fullExp);
return !options.unwrapPromises
? function cspSafeGetter(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
if (!key1 || pathVal == null) return pathVal;
pathVal = pathVal[key1];
if (!key2 || pathVal == null) return pathVal;
pathVal = pathVal[key2];
if (!key3 || pathVal == null) return pathVal;
pathVal = pathVal[key3];
if (!key4 || pathVal == null) return pathVal;
pathVal = pathVal[key4];
return pathVal;
}
: function cspSafePromiseEnabledGetter(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope,
promise;
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key1 || pathVal == null) return pathVal;
pathVal = pathVal[key1];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key2 || pathVal == null) return pathVal;
pathVal = pathVal[key2];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key3 || pathVal == null) return pathVal;
pathVal = pathVal[key3];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
if (!key4 || pathVal == null) return pathVal;
pathVal = pathVal[key4];
if (pathVal && pathVal.then) {
promiseWarning(fullExp);
if (!("$$v" in pathVal)) {
promise = pathVal;
promise.$$v = undefined;
promise.then(function(val) { promise.$$v = val; });
}
pathVal = pathVal.$$v;
}
return pathVal;
};
}
function simpleGetterFn1(key0) {
return function simpleGetterFn1(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
return pathVal == null ? pathVal : pathVal[key0];
};
}
function simpleGetterFn2(key0, key1) {
return function simpleGetterFn2(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
return pathVal == null ? pathVal : pathVal[key1];
};
}
function simpleGetterFn3(key0, key1, key2) {
return function simpleGetterFn3(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
try {
return pathVal[key0][key1][key2];
} catch (e) {
return null;
}
};
}
function simpleGetterFn4(key0, key1, key2, key3, fullExp) {
ensureSafeMemberName(key0, fullExp);
ensureSafeMemberName(key1, fullExp);
ensureSafeMemberName(key2, fullExp);
ensureSafeMemberName(key3, fullExp);
return function simpleGetterFn4(scope, locals) {
var pathVal = (locals && locals.hasOwnProperty(key0)) ? locals : scope;
if (pathVal == null) return pathVal;
pathVal = pathVal[key0];
if (pathVal == null) return pathVal;
pathVal = pathVal[key1];
if (pathVal == null) return pathVal;
pathVal = pathVal[key2];
return pathVal == null ? pathVal : pathVal[key3];
};
}
function getterFn2(path, options, fullExp) {
var pathKeys = path.split('.'),
pathKeysLength = pathKeys.length,
fn;
// For short
if (!options.noNew && pathKeysLength === 1) {
fn = simpleGetterFn1(pathKeys[0], fullExp);
} else if (!options.noNew && pathKeysLength === 2) {
fn = simpleGetterFn2(pathKeys[0], pathKeys[1], fullExp);
} else if (!options.noNew && pathKeysLength === 3) {
fn = simpleGetterFn3(pathKeys[0], pathKeys[1], pathKeys[2], fullExp);
} else if (!options.noNew && pathKeysLength === 4) {
fn = simpleGetterFn4(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], fullExp);
} else if (!options.noNew && pathKeysLength < 6) {
fn = cspSafeGetterFn2(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
options);
} else if (options.csp) {
if (pathKeysLength < 6) {
fn = cspSafeGetterFn2(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp,
options);
} else {
fn = function(scope, locals) {
var i = 0, val;
do {
val = cspSafeGetterFn2(pathKeys[i++], pathKeys[i++], pathKeys[i++], pathKeys[i++],
pathKeys[i++], fullExp, options)(scope, locals);
locals = undefined; // clear after first iteration
scope = val;
} while (i < pathKeysLength);
return val;
};
}
} else {
var code = options.unwrapPromises ? 'var p;\n' : '';
forEach(pathKeys, function(key, index) {
ensureSafeMemberName(key, fullExp);
code += 'if(s == null) return s;\n' +
's='+ (index
// we simply dereference 's' on any .dot notation
? 's'
// but if we are first then we check locals first, and if so read it first
: '((k&&k.hasOwnProperty("' + key + '"))?k:s)') + '["' + key + '"]' + ';\n' +
(options.unwrapPromises
? 'if (s && s.then) {\n' +
' pw("' + fullExp.replace(/(["\r\n])/g, '\\$1') + '");\n' +
' if (!("$$v" in s)) {\n' +
' p=s;\n' +
' p.$$v = undefined;\n' +
' p.then(function(v) {p.$$v=v;});\n' +
'}\n' +
' s=s.$$v\n' +
'}\n'
: '');
});
code += 'return s;';
//var d = performance.now();
/* jshint -W054 */
var evaledFnGetter = new Function('s', 'k', 'pw', code); // s=scope, k=locals, pw=promiseWarning
// window.t += performance.now() - d; window.c++;
/* jshint +W054 */
evaledFnGetter.toString = valueFn(code);
//var evaledFnGetter = cspSafeGetterFn(pathKeys[0], pathKeys[1], pathKeys[2], pathKeys[3], pathKeys[4], fullExp, options);
fn = options.unwrapPromises ? function(scope, locals) {
return evaledFnGetter(scope, locals, promiseWarning);
} : evaledFnGetter;
}
// Only cache the value if it's not going to mess up the cache object
// This is more performant that using Object.prototype.hasOwnProperty.call
return fn;
}
evilGetter = getterFn2('a.b.c.d.e', {noNew: 1});
cspGetter = getterFn2('a.b.c.d.e', {noNew: 1, csp: 1});
newHoleGetter = getterFn2('a.b.c.d.e', {});
commonGetter1e = getterFn2('a', {noNew: 1});
commonGetter1c = getterFn2('a', {noNew: 1, csp: 1});
commonGetter1n = getterFn2('a', {});
commonGetter2e = getterFn2('a.b', {noNew: 1});
commonGetter2c = getterFn2('a.b', {noNew: 1, csp: 1});
commonGetter2n = getterFn2('a.b', {});
commonGetter3e = getterFn2('a.b.c', {noNew: 1});
commonGetter3c = getterFn2('a.b.c', {noNew: 1, csp: 1});
commonGetter3n = getterFn2('a.b.c', {});
commonGetter4e = getterFn2('a.b.c.d', {noNew: 1});
commonGetter4c = getterFn2('a.b.c.d', {noNew: 1, csp: 1});
commonGetter4n = getterFn2('a.b.c.d', {});
completeObj = {a: { b: { c: { d: { e: { f: 23 } } } } } };
locals = {a: { b: { c: { d: { e: { f: 23 } } } } } };
incompleteObj = {a: { b: {} } };
function forEach(array, iterator) {
for(var i=0, ii=array.length; i < ii; i++) {
iterator(array[i], i);
}
}
function ensureSafeMemberName() {}
function valueFn(v) {return function() {return v;};}
Ready to run.
Test | Ops/sec | |
---|---|---|
Evil |
| ready |
CSP |
| ready |
New |
| ready |
Evil 1 arg |
| ready |
CSP 1 arg |
| ready |
New 1 arg |
| ready |
Evil 2 arg |
| ready |
New 2 arg |
| ready |
Evil 3 arg |
| ready |
New 3 arg |
| ready |
Evil 4 arg |
| ready |
New 4 arg |
| ready |
Create evil |
| ready |
Create new |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.