knockout attribute data bindings vs looser data bindings

Benchmark created by Anas Nakawa on


Description

difference between writing data binds as string in dom element attribute, and writing them externally in a js object

Preparation HTML

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<div id="koNativeApp">
    <span data-bind="foreach: data">
        <span data-bind="text: $data"></span>
    </span>
</div>

<br /><br />

<div id="koLooserApp">
    <span data-class="loop">
        <span data-class="setText"></span>
    </span>
</div>

Setup

// normal app
    var koNativeData = ko.observableArray();
    var koNativeViewModel = {data: koNativeData};
    
    ko.applyBindings(koNativeViewModel, document.getElementById('koNativeApp'));
    
    var koNativeClear = function (){
        koNativeData.splice(0, koNativeData().length);
    };
    
    var koNativePush = function (data){
        koNativeData.push(data);
    };
    
    // looser data binding app
    var customBindingProvider = function (bindingObject) {
        this.bindingObject = bindingObject;
        //determine if an element has any bindings
        this.nodeHasBindings = function (node) {
            return node.getAttribute ? node.getAttribute("data-class") : false;
        };
        // return the bindings given a node and the bindingContext
        this.getBindings = function (node, bindingContext) {
            var result = {};
            var classes = node.getAttribute( "data-class" );
            if (classes) {
                classes = classes.split(' ');
                //evaluate each class, build a single object to return
                for (var i = 0, j = classes.length; i < j; i++) {
                    var bindingAccessor = this.bindingObject[classes[i]];
                    if (bindingAccessor) {
                        var binding = typeof bindingAccessor == "function" ? bindingAccessor.call(bindingContext.$data) : bindingAccessor;
                        $.extend(result, binding);
                    }
                }
            }
            return result;
        };
    };
    
    var koLooserData = ko.observableArray();
    var koLooserViewModel = {data: koLooserData};
    
    var koLooserBindings = {
        'loop': { foreach: koLooserViewModel.data },
        'setText': function() { return { text: this }; } 
    };
    
    ko.bindingProvider.instance = new customBindingProvider(koLooserBindings);
    
    ko.applyBindings(koLooserViewModel, document.getElementById('koLooserApp'));
    
    var koLooserClear = function (){
        koLooserData.splice(0, koLooserData().length);
    };
    
    var koLooserPush = function (data){
        koLooserData.push(data);
    };
    
    
    ​

Test runner

Ready to run.

Testing in
TestOps/sec
Native Data Bindings
koNativeClear();
for (var i = 0; i < 100; i++)
  koNativePush("koNative");
ready
Looser Data Binding
koLooserClear();
for (var i = 0; i < 100; i++)
  koLooserPush("koLooser");
ready

Revisions

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

  • Revision 1: published by Anas Nakawa on