Changeset 1927 for trunk


Ignore:
Timestamp:
2011-08-09 09:52:26 (10 months ago)
Author:
mpo
Message:

introducing a value-cache on container-controls
improves read-performance at the cost of some cache and invalidation management

gain in tests rather limited however: use cases should have far more reads then writes to benefit.

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/modules/kauri-forms/kauri-forms-framework/src/main/kauri/static-{build}.key/kauri.forms/control.js

    r1920 r1927  
    20972097    } 
    20982098     
     2099     
    20992100    $.inherit(AbstractContainerControl, Control); 
    21002101     
     
    21222123    }; 
    21232124     
     2125    var CLEAR = {}; 
     2126    AbstractContainerControl.prototype.invalidateValueCache = function() { 
     2127        this.value = CLEAR; 
     2128        this.cachedWireValue = CLEAR; 
     2129    }; 
    21242130 
    21252131    /**  
     
    22252231     */ 
    22262232    AbstractContainerControl.prototype.setLoop = function(fn, value, noValidation){ 
    2227         // ignore childUpdates 
    2228         var restore = this.updateValue; 
    2229         this.updateValue = function(childControl){ 
    2230         }; 
    22312233         
    22322234        var cfn = function(i, child) { 
     
    22342236            fn(i, child, childValue, noValidation); 
    22352237        }; 
    2236         this.internalSetLoop(cfn, value); 
    2237          
    2238         // reset childUpdates 
    2239         this.updateValue = restore;         
     2238         
     2239        var me = this; 
     2240 
     2241        this.silenceEventsWhile(function() { // ignore childUpdates 
     2242            me.internalSetLoop(cfn, value); 
     2243        }); 
     2244         
    22402245        // call childUpdates 
    22412246        this.updateValue(noValidation); 
     
    22832288     */ 
    22842289    AbstractContainerControl.prototype.getValue = function(){ 
    2285         return this.getLoop(AbstractContainerControl.childGetter); 
     2290        if (this.value == CLEAR){ 
     2291            this.value = this.getLoop(AbstractContainerControl.childGetter); 
     2292        } 
     2293        return this.value; 
    22862294    }; 
    22872295    AbstractContainerControl.childGetter = function(i, child) { 
     
    23072315     */ 
    23082316    AbstractContainerControl.prototype.getWireValue = function(){ 
    2309         var w = this.getLoop(AbstractContainerControl.childWireGetter);   
    2310         return this.getType().toWireValue(w); // allow composite-type specific formatting (merge) 
     2317        if (this.cachedWireValue == CLEAR) { 
     2318            var w = this.getLoop(AbstractContainerControl.childWireGetter);   
     2319            this.cachedWireValue = this.getType().toWireValue(w); // allow composite-type specific formatting (merge) 
     2320        } 
     2321        return this.cachedWireValue; 
    23112322    }; 
    23122323    AbstractContainerControl.childWireGetter = function(i, child) { 
     
    23412352            Control.reset(me); 
    23422353        } 
     2354        me.invalidateValueCache(); 
    23432355    }; 
    23442356     
     
    26392651         
    26402652        childControl.valueChanged(childChanged); 
    2641          
     2653 
    26422654        return childControl; 
    26432655    } 
     
    26512663     
    26522664        this._children[id] = childControl; 
    2653     } 
    2654  
    2655      /** 
    2656       * Deletes a child control in the list of this controls children 
    2657       * @param {String} id 
    2658       */ 
    2659      AbstractContainerControl.prototype.deleteChild = function(id){ 
     2665        this.updateValue(true, true); // be sure to handle change in value structure 
     2666    } 
     2667 
     2668    /** 
     2669     * Deletes a child control in the list of this controls children 
     2670     * @param {String} id 
     2671     */ 
     2672    AbstractContainerControl.prototype.deleteChild = function(id){ 
    26602673      
    2661          delete this._children[id]; 
    2662      } 
     2674        delete this._children[id]; 
     2675        this.updateValue(true, true); // be sure to handle change in value structure 
     2676    } 
    26632677 
    26642678      
     
    26662680     * Runs validation on this control and acknowledges a change in value 
    26672681     * @param {Boolean} noValidation perform validation or not 
    2668      */ 
    2669     AbstractContainerControl.prototype.updateValue = function(noValidation){ 
    2670         var value = this.getValue(); 
    2671         var nvalue = this.normaliseValue(value); 
    2672         if (!$.valueCompare(value, nvalue)) { // validation & update event only needed if there are actual changes to the normalised valued 
    2673             var restore = this.updateValue; 
    2674             this.updateValue = function(noValidation) {} 
    2675             this.setNormalisedValue(nvalue); 
    2676             this.updateValue = restore; 
    2677         } 
    2678         if(!noValidation) { 
    2679             this.newValidation(this.getValue(), this.getWireValue()); 
    2680         } 
    2681         this.valueChanged(); 
     2682     * @param {Boolean} noValueAccess avoid accessing the value, just clear cache and notify parent 
     2683     */ 
     2684    AbstractContainerControl.prototype.updateValue = function(noValidation, noValueAccess){ 
     2685        noValueAccess = noValueAccess || false; 
     2686        this.invalidateValueCache(); // be sure to read children again 
     2687        if (!noValueAccess) { 
     2688            var value = this.getValue(); 
     2689            var nvalue = this.normaliseValue(value); 
     2690            if (!$.valueCompare(value, nvalue)) { // validation & update event only needed if there are actual changes to the normalised valued 
     2691                var me = this; 
     2692                this.silenceEventsWhile(function() { 
     2693                    me.setNormalisedValue(nvalue); 
     2694                }); 
     2695            } 
     2696            if(!noValidation) { 
     2697                this.newValidation(this.getValue(), this.getWireValue()); 
     2698            } 
     2699        } 
     2700        this.valueChanged();         // and notify parent 
    26822701     } 
     2702      
     2703    /** 
     2704     *  
     2705     */ 
     2706    AbstractContainerControl.prototype.silenceEventsWhile = function(action) { 
     2707        var restoreUpdateFn = this.updateValue; 
     2708        this.updateValue = function(noValidation) {}; 
     2709         
     2710        action(); 
     2711         
     2712        this.updateValue = restoreUpdateFn; 
     2713    }   
    26832714     
    26842715    /** 
  • trunk/modules/kauri-forms/kauri-forms-framework/src/test/kauri.forms/test-collection.js

    r1921 r1927  
    179179     
    180180    // test 
    181     expect(10); 
     181    expect(11); 
    182182 
    183183    // verify creation of control 
     
    207207    equal(c.getElement("messages").html(), $("<p>Length not in range 3 &#x2a7d; Length &#x2a7e; 6.</p>").html(), "validation error set correctly"); 
    208208     
    209     c.addChild().getElement("input").val(okValue + "4").change(); 
    210     equal(changes, 4, "change detection"); 
     209    var newRow = c.addChild(); 
     210    equal(changes, 4, "change detection"); // NOTE: both addchild and the actual value change will trigger an update! 
     211    newRow.getElement("input").val(okValue + "4").change(); 
     212    equal(changes, 5, "change detection");  
    211213 
    212214    equal(c.getElement("messages").html(), "", "validation error cleared"); 
  • trunk/modules/kauri-forms/kauri-forms-framework/src/test/kauri.forms/test-form.js

    r1908 r1927  
    711711    expect(5); 
    712712     
    713     ok($.valueCompare(form.getValue(), {td: "s"}), "checking expected initial value."); 
     713    deepEqual(form.getValue(), {td: "s"}, "checking expected initial value."); 
    714714    var tds = form.findControl("tds");  
    715715    tds.getChildByIndex(1); // force creation of children... 
    716716     
    717     ok($.valueCompare(form.getValue(), {td: "s", tds: ["s", "s"]}), "checking expected initial values inside the collection as well."); 
     717    deepEqual(form.getValue(), {td: "s", tds: ["s", "s"]}, "checking expected initial values inside the collection as well."); 
    718718    form.delegate("testDelegate", "x"); 
    719     ok($.valueCompare(form.getValue(), {td: "sx", tds: ["sx", "sx"]}), "checking all modified."); 
     719    deepEqual(form.getValue(), {td: "sx", tds: ["sx", "sx"]}, "checking all modified."); 
    720720    form.findControl("tds").delegate("testDelegate", "x"); 
    721     ok($.valueCompare(form.getValue(), {td: "sx", tds: ["sxx", "sxx"]}), "checking all modified in collection."); 
     721    deepEqual(form.getValue(), {td: "sx", tds: ["sxx", "sxx"]}, "checking all modified in collection."); 
    722722    form.findControl("tds/1").delegate("testDelegate", "x"); 
    723     ok($.valueCompare(form.getValue(), {td: "sx", tds: ["sxx", "sxxx"]}), "checking single modified."); 
     723    deepEqual(form.getValue(), {td: "sx", tds: ["sxx", "sxxx"]}, "checking single modified."); 
    724724     
    725725     
  • trunk/samples/kauri-forms-sample/src/main/kauri/pages/collection-performance.html.xml

    r1757 r1927  
    1212      var days = ["mo", "tu", "we", "th", "fr", "sa", "su"]; 
    1313       
    14       function getData() { 
     14      function getData(size) { 
    1515          var data = { 
    1616              "performances": [ 
     
    1818          } 
    1919     
    20           for (var i = 0; i < 5; i++) { 
     20          for (var i = 0; i < size; i++) { 
    2121            data.performances[i] = { "task": "Task " + i}; 
    2222            for (var j = 0; j < days.length; j++) { 
     
    3030      $(function() { 
    3131          var form1 = new $.org.kauriproject.forms.Form("form1", {}); 
     32           
     33          var doTimed = function(fn) { 
     34              var t0 = (new Date()).getTime(); 
     35              fn(); 
     36              return (new Date()).getTime() - t0; 
     37          } 
    3238 
    3339          $("#loadWireSampleData").click(function() { 
    34               form1.setWireValue(getData());               
     40              var data = getData($("#size").val()); 
     41              var dt = doTimed(function() { 
     42                  form1.setWireValue(data); 
     43              }); 
     44              $("#timing").text(dt); 
    3545          }); 
    3646 
    37           $("#loadWireSampleData100").click(function() { 
     47          $("#loadWireSampleDataRepeat").click(function() { 
    3848              var intervalHandle; 
    39               var tcount = 100; 
     49              var tcount = $("#repeats").val(); 
    4050              var t = function() { 
    4151                  $("#countdown").text(tcount); 
     
    5060 
    5161          $("#loadNativeSampleData").click(function() { 
    52               form1.setValue(getData());               
     62              var data = getData($("#size").val()); 
     63              var dt = doTimed(function() { 
     64                  form1.setValue(getData($("#size").val()));               
     65              }); 
     66              $("#timing2").text(dt); 
    5367          }); 
    5468 
    55           $("#loadNativeSampleData100").click(function() { 
    56               debugger; 
     69          $("#loadNativeSampleDataRepeat").click(function() { 
    5770              var intervalHandle; 
    58               var tcount = 100; 
     71              var tcount = $("#repeats").val(); 
    5972              var t = function() { 
    6073                  $("#countdown2").text(tcount); 
     
    96109    <p>Press the load sample data button below to test.</p> 
    97110 
    98     <p><button id="loadWireSampleData">Load sample data via setWireValue()</button></p> 
    99  
    100     <p><button id="loadWireSampleData100">100 times Load sample data via setWireValue()</button></p> 
    101     <div id="countdown"/> 
    102  
    103     <p><button id="loadNativeSampleData">Load sample data via setValue()</button></p> 
    104  
    105     <p><button id="loadNativeSampleData100">100 times Load sample data via setValue()</button></p> 
    106     <div id="countdown2"/> 
     111    <p>Load Sample Data: 
     112    <table style="width: auto; border: 1px solid black;"> 
     113      <tbody> 
     114        <tr> 
     115          <td>containing <input id="size" value="5" size="3"/> rows</td> 
     116          <td><button id="loadWireSampleData">via setWireValue()</button> <span id="timing">0</span> ms</td> 
     117          <td><button id="loadNativeSampleData">via setValue()</button> <span id="timing2">0</span> ms</td> 
     118        </tr> 
     119        <tr> 
     120          <td>and repeat that <input id="repeats" value="100" size="3"/> times</td> 
     121          <td><button id="loadWireSampleDataRepeat">via setWireValue()</button>&#160;<span id="countdown">0</span></td> 
     122          <td><button id="loadNativeSampleDataRepeat">via setValue()</button>&#160;<span id="countdown2">0</span></td> 
     123        </tr> 
     124      </tbody> 
     125    </table>     
     126    </p> 
    107127 
    108128    <p><button id="addEmptyRows">Add 30 empty rows</button></p> 
Note: See TracChangeset for help on using the changeset viewer.