ko.viewmodel vs ko.mapping vs knockout.wrap vs custom (v19)

Revision 19 of this benchmark created by Aymeric on


Description

Performance comparison between the knockout mapping plugins ko.viewmodel and ko.mapping and knockout.wrap

Added custom mapper code

Preparation HTML

<script src="http://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.1/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 src="https://raw.github.com/arj03/knockout.wrap/master/knockout.wrap.js"></script>

Setup

ko.mapper = {
        isFunction: function(functionToCheck) {
             var getType = {};
            return functionToCheck && getType.toString.call(functionToCheck) === '[object Function]';
        },
        fromJS: function (raw, mappingOptions, target) {
            var self = this;
            mappingOptions = mappingOptions || {};
            target = target || {};
            for (var property in raw) {
    
                if (raw[property] instanceof Array) {
                    var createItem = function(options) { return self.mapProperty(options); };
    
                    if (mappingOptions[property]) {
                        createItem = mappingOptions[property].create;
                    }
    
                    var arrayToSet = raw[property].map(function(item) {
                        return createItem({ data: item, property: property, mapping: mappingOptions });
                    });
                    
                    if (this.isFunction(target[property])) {
                        target[property](arrayToSet);
                    } else {
                        target[property] = ko.observableArray(arrayToSet);
                    }
    
                } else {
                    this.setProperty(target, property, {data: raw[property], property: property, mapping: mappingOptions });
                }
            }
            return target;
        },
        setProperty: function (target, property, options) {
            if (options.mapping[options.property]) {
                target[property] = options.mapping[options.property].create({ data: options.data });
                return;
            }
    
            if (options.data != null && typeof options.data === 'object') {
                var obj = target[property] || {};
                target[property] = this.fromJS(options.data, options.mapping, obj);
            } else {
                if (this.isFunction(target[property])) {
                    target[property](options.data);
                } else {
                    target[property] = ko.observable(options.data);
                }
            }
        },
        mapProperty: function (options) {
            if (options.mapping[options.property]) {
                return options.mapping[options.property].create({data: options.data});
            }
    
            if (options.data != null && typeof options.data === 'object') {
                return this.fromJS(options.data, options.mapping, {});
            } else {
                return ko.observable(options.data);
            }
    
        }
    };
    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"}] 
            }      
        });   
            
    }

Test runner

Ready to run.

Testing in
TestOps/sec
ko.mapping
viewmodel = ko.mapping.fromJS(model);
ready
ko.viewmodel
viewmodel = ko.viewmodel.fromModel(model);
ready
knockout.wrap
viewmodel = ko.wrap.fromJS(model);
ready
custom mapper
viewmodel = ko.mapper.fromJS(model);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.