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
Performance comparison between the knockout mapping plugins ko.viewmodel and ko.mapping and knockout.wrap
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/3.0.0/knockout-min.js"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout.mapping/2.3.5/knockout.mapping.js"></script>
<script src="http://coderenaissance.github.com/knockout.viewmodel/knockout.viewmodel.min.js"></script>
<script>
// Knockout Fast Mapping v0.1
// License: MIT (http://www.opensource.org/licenses/mit-license.php)
(function (factory) {
// Module systems magic dance.
if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
// CommonJS or Node: hard-coded dependency on "knockout"
factory(require("knockout"), exports);
} else if (typeof define === "function" && define["amd"]) {
// AMD anonymous module with hard-coded dependency on "knockout"
define(["knockout", "exports"], factory);
} else {
// <script> tag: use the global `ko` object, attaching a `wrap` property
factory(ko, ko.wrap = {});
}
}(function (ko, exports) {
// this function mimics ko.mapping
exports.fromJS = function(jsObject, computedFunctions)
{
reset();
return wrap(jsObject, computedFunctions);
}
// this function unwraps the outer for assigning the result to an observable
// see https://github.com/SteveSanderson/knockout/issues/517
exports.updateFromJS = function(observable, jsObject, computedFunctions)
{
reset();
return observable(ko.utils.unwrapObservable(wrap(jsObject, computedFunctions)));
}
exports.fromJSON = function (jsonString, computedFunctions) {
var parsed = ko.utils.parseJson(jsonString);
arguments[0] = parsed;
return exports.fromJS.apply(this, computedFunctions);
};
exports.toJS = function (observable) {
return unwrap(observable);
}
exports.toJSON = function (observable) {
var plainJavaScriptObject = exports.toJS(observable);
return ko.utils.stringifyJson(plainJavaScriptObject);
};
function typeOf(value) {
var s = typeof value;
if (s === 'object') {
if (value) {
if (value.constructor == Date)
s = 'date';
else if (Object.prototype.toString.call(value) == '[object Array]')
s = 'array';
} else {
s = 'null';
}
}
return s;
}
// unwrapping
function unwrapObject(o)
{
var t = {};
for (var k in o)
{
var v = o[k];
if (ko.isComputed(v))
continue;
t[k] = unwrap(v);
}
return t;
}
function unwrapArray(a)
{
var r = [];
if (!a || a.length == 0)
return r;
for (var i = 0, l = a.length; i < l; ++i)
r.push(unwrap(a[i]));
return r;
}
function unwrap(v)
{
var isObservable = ko.isObservable(v);
if (isObservable)
{
var val = v();
if (typeOf(val) == "array")
{
return unwrapArray(val);
}
else
{
return val;
}
}
else
{
if (typeOf(v) == "array")
{
return unwrapArray(v);
}
else if (typeOf(v) == "object")
{
return unwrapObject(v);
}
else
{
return v;
}
}
}
function reset()
{
parents = [{obj: null, wrapped: null, lvl: ""}];
}
// wrapping
function wrapObject(o, computedFunctions)
{
// check for infinite recursion
for (var i = 0; i < parents.length; ++i) {
if (parents[i].obj === o) {
return parents[i].wrapped;
}
}
var t = {};
for (var k in o)
{
var v = o[k];
parents.push({obj: o, wrapped: t, lvl: currentLvl() + "/" + k});
t[k] = wrap(v, computedFunctions);
parents.pop();
}
if (computedFunctions && computedFunctions[currentLvl()])
t = computedFunctions[currentLvl()](t);
if (hasES5Plugin())
ko.track(t);
return t;
}
function wrapArray(a, computedFunctions)
{
var r = ko.observableArray();
if (!a || a.length == 0)
return r;
for (var i = 0, l = a.length; i < l; ++i)
r.push(wrap(a[i], computedFunctions));
return r;
}
// a stack, used for two purposes:
// - circular reference checking
// - computed functions
var parents;
function currentLvl()
{
return parents[parents.length-1].lvl;
}
function wrap(v, computedFunctions)
{
if (typeOf(v) == "array")
{
return wrapArray(v, computedFunctions);
}
else if (typeOf(v) == "object")
{
return wrapObject(v, computedFunctions);
}
else
{
if (!hasES5Plugin())
{
var t = ko.observable();
t(v);
return t;
} else
return v;
}
}
function hasES5Plugin()
{
return ko.track != null;
}
}));
</script>
var numberOfArrayRecords = 100,
viewmodel = null,
model = {
items: []
};
for (var x = 0; x < numberOfArrayRecords; x++) {
model.items.push({
string: "Test",
number: 4,
anotherObject: {
items: [{
id: 4,
name: "Test"
}, {
id: 7,
name: "Test2"
}]
}
});
}
Ready to run.
Test | Ops/sec | |
---|---|---|
ko.mapping |
| ready |
ko.viewmodel |
| ready |
knockout.wrap |
| ready |
You can edit these tests or add more tests to this page by appending /edit to the URL.