Skip to content

Commit

Permalink
performance optimizations
Browse files Browse the repository at this point in the history
  • Loading branch information
justinbmeyer authored and daffl committed Jun 10, 2014
1 parent ed24af0 commit 4aa9f47
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 44 deletions.
56 changes: 36 additions & 20 deletions compute/compute.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,29 +126,38 @@ steal('can/util', 'can/util/bind', 'can/util/batch', function (can, bind) {
obEv,
name;
// Go through what needs to be observed.
for( name in newObserveSet ) {

if( oldObserved[name] ) {
// After binding is set up, values
// in `oldObserved` will be unbound. So if a name
// has already be observed, remove from `oldObserved`
// to prevent this.
delete oldObserved[name];
} else {
// If current name has not been observed, listen to it.
obEv = newObserveSet[name];
obEv.obj.bind(obEv.event, onchanged);
}
bindNewSet(oldObserved, newObserveSet, onchanged);
unbindOldSet(oldObserved, onchanged);

return info;
};
// This will not be optimized.
var bindNewSet = function(oldObserved, newObserveSet, onchanged){
for(var name in newObserveSet ) {
bindOrPreventUnbinding(oldObserved, newObserveSet, name, onchanged);
}

// Iterate through oldObserved, looking for observe/attributes
// that are no longer being bound and unbind them.
for ( name in oldObserved) {
};
// This will be optimized.
var bindOrPreventUnbinding = function(oldObserved, newObserveSet, name, onchanged){
if( oldObserved[name] ) {
// After binding is set up, values
// in `oldObserved` will be unbound. So if a name
// has already be observed, remove from `oldObserved`
// to prevent this.
delete oldObserved[name];
} else {
// If current name has not been observed, listen to it.
obEv = newObserveSet[name];
obEv.obj.bind(obEv.event, onchanged);
}
};
// Iterate through oldObserved, looking for observe/attributes
// that are no longer being bound and unbind them.
var unbindOldSet = function(oldObserved, onchanged){
for (var name in oldObserved) {
obEv = oldObserved[name];
obEv.obj.unbind(obEv.event, onchanged);
}

return info;
};

// ### updateOnChange
Expand Down Expand Up @@ -257,14 +266,21 @@ steal('can/util', 'can/util/bind', 'can/util/batch', function (can, bind) {
},
setCached = set,
// Save arguments for cloning
args = can.makeArray(arguments),
args = [],
// updater for when value is changed
updater = function (newValue, oldValue, batchNum) {
setCached(newValue);
updateOnChange(computed, newValue,oldValue, batchNum);
},
// the form of the arguments
form;


// convert arguments to args to make V8 Happy
for(var i = 0, arglen = arguments.length; i< arglen; i++){
args[i] = arguments[i];
}

computed = function (newVal) {
// If the computed function is called with arguments,
// a value should be set
Expand Down
3 changes: 3 additions & 0 deletions map/bubble.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ steal('can/util', function(can){
can.stopListening.call(parent, child, eventName);
}
},
isBubbling: function(parent, eventName){
return parent._bubbleBindings && parent._bubbleBindings[eventName];
},
bind: function(parent, eventName) {
if (!parent._init ) {
var bubbleEvent = bubble.event(parent, eventName);
Expand Down
32 changes: 21 additions & 11 deletions map/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -300,17 +300,24 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc
target: ev.target
}, [newVal, oldVal]);


},
// Trigger a change event.
_triggerChange: function (attr, how, newVal, oldVal) {
// so this change can bubble ... a bubbling change triggers the
// _changes trigger
if(bubble.isBubbling(this, "change")) {
can.batch.trigger(this, "change", [attr, how, newVal, oldVal]);
} else {
can.batch.trigger(this, attr, [newVal, oldVal]);
}

if(how === "remove" || how === "add") {
can.batch.trigger(this, {
type: "__keys",
batchNum: ev.batchNum
type: "__keys"
});
}
},
// Trigger a change event.
_triggerChange: function (attr, how, newVal, oldVal) {
can.batch.trigger(this, "change", arguments);
},
// Iterator that does not trigger live binding.
_each: function (callback) {
var data = this.__get();
Expand Down Expand Up @@ -384,21 +391,24 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc
// Reads a property from the `object`.
_get: function (attr) {
var value;

// Handles the case of a key having a `.` in its name
if (typeof attr === 'string' && !! ~attr.indexOf('.')) {
// Otherwise we have to dig deeper into the Map to get the value.
if( typeof attr === 'string' && !! ~attr.indexOf('.') ) {
// Attempt to get the value
value = this.__get(attr);
// For keys with a `.` in them, value will be defined
if (value !== undefined) {
return value;
}
}

// Otherwise we have to dig deeper into the Map to get the value.

// First, break up the attr (`"foo.bar"`) into parts like `["foo","bar"]`.
var parts = can.Map.helpers.attrParts(attr),
// Then get the value of the first attr name (`"foo"`).
current = this.__get(parts.shift());


// If there are other attributes to read...
return parts.length ?
// and current has a value...
Expand Down Expand Up @@ -475,7 +485,7 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc
if (value !== current) {
// Check if we are adding this for the first time --
// if we are, we need to create an `add` event.
var changeType = this.__get()
var changeType = current !== undefined || this.__get()
.hasOwnProperty(prop) ? "set" : "add";

// Set the value on `_data` and hook it up to send event.
Expand All @@ -500,7 +510,7 @@ steal('can/util', 'can/util/bind','./bubble.js', 'can/construct', 'can/util/batc
}
// Add property directly for easy writing.
// Check if its on the `prototype` so we don't overwrite methods like `attrs`.
if (!can.isFunction(this.constructor.prototype[prop]) && !this._computedBindings[prop] ) {
if (! typeof this.constructor.prototype[prop] === 'function' && !this._computedBindings[prop] ) {
this[prop] = val;
}
},
Expand Down
11 changes: 7 additions & 4 deletions map/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,13 @@ <h2 id="qunit-userAgent"></h2>
}

QUnit.config.autostart = false;
steal("can/map/map_test.js", function() {
can.dev.logLevel = 3;
QUnit.start();
});
setTimeout(function(){
steal("can/map/map_test.js", function() {
can.dev.logLevel = 3;
QUnit.start();
});
},300);

</script>
</body>
</html>
1 change: 1 addition & 0 deletions util/batch/batch.js
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ steal('can/util/can.js', function (can) {
* immediately.
*/
trigger: function (item, event, args) {
//console.log(event, item, args);
// Don't send events if initalizing.
if (!item._init) {
if (transactions === 0) {
Expand Down
2 changes: 1 addition & 1 deletion util/can.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ steal(function () {
can.isDeferred = function (obj) {
var isFunction = this.isFunction;
// Returns `true` if something looks like a deferred.
return obj && isFunction(obj.then) && isFunction(obj.pipe);
return obj && typeof obj.then === "function" && typeof obj.pipe === "function";
};

var cid = 0;
Expand Down
26 changes: 18 additions & 8 deletions view/stache/visual_benchmark.html
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
var template = stache(
"{{#each boxes}}"+
"<div class='box-view'>"+
"<div class='box' id='box-{{number}}' style='top: {{top}}px; left: {{left}}px; background: rgb(0,0,{{color}});'>"+
"<div class='box' id='box-{{number}}' style='{{style}}'>"+
"{{content}}"+
"</div>"+
"</div>"+
Expand All @@ -63,21 +63,30 @@

var boxes = new can.List(),
Box = can.Map.extend({
count: 0,
content: 0,
tick: function(){
var count = this.attr('count') + 1;
top: 0,
left: 0,
content: 0,
count: 0,

tick: function() {
var count = this.attr('count') + 1;

this.attr('count', count);
this.attr('top', Math.sin(count / 10) * 10);
this.attr('left', Math.cos(count / 10) * 10);
this.attr('color', count % 255);
this.attr('content', count % 100);
}
this.attr('style', this.computeStyle());

},

computeStyle: function() {
return 'top: ' + this.attr('top') + 'px; left: ' + this.attr('left') +'px; background: rgb(0,0,' + this.attr('color') + ');';
}
});

for(var i =0; i < 100; i++) {
var box = new Box({ number: i });
box.tick();
boxes.push( box );
}

Expand All @@ -103,6 +112,7 @@
benchmarkLoop(run);
});



window.timeout = null;
window.totalTime = null;
Expand All @@ -116,7 +126,7 @@
if (loopCount % 20 === 0) {
$('#timing').text('Performed ' + loopCount + ' iterations in ' + totalTime + ' ms (average ' + (totalTime / loopCount).toFixed(2) + ' ms per loop).');
}
if(loopCount < 10) {
if(loopCount < 1000) {
timeout = setTimeout(function(){
benchmarkLoop(fn);
},1);
Expand Down

0 comments on commit 4aa9f47

Please sign in to comment.