Last active
August 29, 2015 14:07
-
-
Save pherris/5f49737dfb06716634f8 to your computer and use it in GitHub Desktop.
Ext Element Cache with MutationSummary Library
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>ExtJS Cache Example</title> | |
<link href="http://cdn.sencha.com/ext/gpl/4.2.0/resources/css/ext-all.css" rel="stylesheet" /> | |
<script src="http://cdn.sencha.com/ext/gpl/4.2.0/ext-all-debug.js"></script> | |
<body> | |
</body> | |
<script> | |
/** | |
* this file shows an example of caching the width and height attributes of DOM elements | |
* in ExtJS when calling the getters and clearing the cache with the setters AND with the | |
* MutationObserver (NOT MUTATIONSUMMARY) functionality to detect attribute changes. | |
* | |
* This implementation also has the potential to be a little race-condition-y but | |
* demonstrates the concept and gaps well enough. | |
* | |
*/ | |
Ext.application({ | |
name : 'Fiddle', | |
launch : function() { | |
Ext.define('Rally.ui.overrides.Element', { | |
override: 'Ext.dom.Element', | |
cachedHeight: null, | |
cachedWidth: null, | |
_clearCache: function () { | |
console.log('clear cache'); | |
this.cachedHeight = null; | |
this.cachedWidth = null; | |
}, | |
setWidth: function (width) { | |
this._clearCache(); | |
this.callParent([width]); | |
}, | |
setHeight: function (height) { | |
this._clearCache(); | |
this.callParent([height]); | |
}, | |
getWidth: function () { | |
if (this.cachedWidth) { | |
console.log('cached w'); | |
} else { | |
this.cachedWidth = this.callParent([]); | |
console.log('non cached w'); | |
} | |
return this.cachedWidth; | |
}, | |
getHeight: function () { | |
if (this.cachedHeight) { | |
console.log('cached h'); | |
} else { | |
this.cachedHeight = this.callParent([]); | |
console.log('non cached h'); | |
} | |
return this.cachedHeight; | |
} | |
}); | |
// create an observer instance | |
var mObserver = new MutationObserver(function(mutations) { | |
var cacheInvalidatedList = {}; | |
mutations.forEach(function(mutation) { | |
if (!mutation.target || !mutation.target.id || cacheInvalidatedList[mutation.target.id] === true) { | |
return; | |
} | |
var extDomElement = Ext.get(mutation.target.id); | |
if (extDomElement._clearCache) { | |
extDomElement._clearCache(); | |
cacheInvalidatedList[mutation.target.id] = true; | |
} | |
}); | |
}); | |
var config = { attributes: true, childList: true, characterData: true, attributeFilter: ['style'] }; | |
var testDiv = Ext.DomHelper.append(Ext.getBody(), '<div id="testDiv" style="border-radius: 10px">observe me!</div>', true); | |
mObserver.observe(testDiv.dom, config); | |
testDiv.setStyle('border', '3px solid #BADA55'); | |
//sets the cache | |
console.log('Default width: ' + testDiv.getWidth()); | |
//change the native DOM style - Ext knows nothing about this, but the mutation observer does | |
testDiv.dom.style.width = 450 + 'px'; | |
console.log('I still have the old value even though the DOM is at 450: ' + testDiv.getWidth()); | |
testDiv.setWidth(450); | |
console.log('I now have the right value (450) since we used a setter to set the size: ' + testDiv.getWidth()); | |
//let the MutationSummary library detect the DOM change and invalidate our cache | |
setTimeout(function () { | |
var radius = Math.floor(Math.random() * 100 ); | |
Ext.get('testDiv').getWidth(); //make sure the wrong value is cached. | |
document.querySelector("#testDiv").style.width = radius + 'px'; | |
console.log('I should NOT have the correct value of ' + radius + ' (race start): ' + Ext.get('testDiv').getWidth()); | |
setTimeout(function () { | |
console.log('I should have the correct value of ' + radius + ' (race condition end): ' + Ext.get('testDiv').getWidth()); | |
}, 0); | |
}, 0); | |
//some performance testing... | |
if (false) { | |
var loopCount = 10000; | |
var start = window.performance.now(); | |
for (i=0;i<loopCount;i++) { | |
Ext.DomHelper.append(Ext.getBody(), '<div id="' + i +'" style="border-radius: 10px">observe me!</div>', true); | |
} | |
var domDone = window.performance.now(); | |
console.log('creating dom took: ' + (domDone-start)); | |
for (i=0;i<loopCount;i++) { | |
for (j=0;j<5;j++) { | |
Ext.get(''+j).getWidth(); | |
} | |
} | |
var getterDone = window.performance.now(); | |
console.log('calling getters took: ' + (getterDone-domDone)); | |
var changeDomDone; | |
setTimeout(function () { | |
for (i=0;i<loopCount;i++) { | |
for (j=0;j<5;j++) { | |
Ext.get(''+i).dom.style.width = j*25 + 'px'; | |
} | |
} | |
changeDomDone = window.performance.now(); | |
console.log('changing dom took : ' + (changeDomDone-getterDone)); | |
}, 0); | |
} | |
} | |
}); | |
</script> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<title>ExtJS Cache Example</title> | |
<script src="../../src/mutation-summary.js"></script> | |
<link href="http://cdn.sencha.com/ext/gpl/4.2.0/resources/css/ext-all.css" rel="stylesheet" /> | |
<script src="http://cdn.sencha.com/ext/gpl/4.2.0/ext-all-debug.js"></script> | |
<body> | |
</body> | |
<script> | |
/** | |
* this file shows an example of caching the width and height attributes of DOM elements | |
* in ExtJS when calling the getters and clearing the cache with the setters AND with the | |
* MutationSummary library to detect attribute changes. | |
* | |
* This has the potential to be a little race-condition-y but demonstrates the concept and gaps well enough. | |
* | |
* Mutation Summary: https://code.google.com/p/mutation-summary/ | |
*/ | |
Ext.application({ | |
name : 'Fiddle', | |
launch : function() { | |
Ext.define('Rally.ui.overrides.Element', { | |
override: 'Ext.dom.Element', | |
cachedHeight: null, | |
cachedWidth: null, | |
_clearCache: function () { | |
this.cachedHeight = null; | |
this.cachedWidth = null; | |
}, | |
setWidth: function (width) { | |
this._clearCache(); | |
this.callParent([width]); | |
}, | |
setHeight: function (height) { | |
this._clearCache(); | |
this.callParent([height]); | |
}, | |
getWidth: function () { | |
if (this.cachedWidth) { | |
Ext.log('cached w'); | |
} else { | |
this.cachedWidth = this.callParent([]); | |
Ext.log('non cached w'); | |
} | |
return this.cachedWidth; | |
}, | |
getHeight: function () { | |
if (this.cachedHeight) { | |
Ext.log('cached h'); | |
} else { | |
this.cachedHeight = this.callParent([]); | |
Ext.log('non cached h'); | |
} | |
return this.cachedHeight; | |
} | |
}); | |
//while this code demonstrates the capability of the MutationSummary library to identify and clear cached DOM | |
// data, there is a possibility of race conditions since this library summarizes changes, and a better | |
// implementation might be the native MutationObserver. | |
var observer = new MutationSummary({ | |
callback: function (mutations) { | |
mutations.forEach(function(mutation) { | |
if (mutation.valueChanged.length > 0) { | |
//look up the Ext dom element, Ext maintains a cache of dom elements by ID | |
mutation.valueChanged.forEach(function(changedDomElement) { | |
var extDomElement = Ext.get(changedDomElement.id); | |
if (extDomElement._clearCache) { | |
extDomElement._clearCache(); | |
} | |
}); | |
} | |
}); | |
}, | |
rootNode: Ext.getBody().dom, | |
queries: [ | |
{ attribute: 'style' } | |
] | |
}); | |
var testDiv = Ext.DomHelper.append(Ext.getBody(), '<div id="testDiv">observe me!</div>', true); | |
testDiv.setStyle('border-radius', '10px'); | |
testDiv.setStyle('border', '3px solid #BADA55'); | |
//sets the cache | |
console.log('Default width: ' + testDiv.getWidth()); | |
//change the native DOM style - Ext knows nothing about this, but the mutation observer does | |
testDiv.dom.style.width = 450; | |
console.log('I still have the old value even though the DOM is at 450: ' + testDiv.getWidth()); | |
testDiv.setWidth(450); | |
console.log('I now have the right value (450) since we used a setter to set the size: ' + testDiv.getWidth()); | |
//let the MutationSummary library detect the DOM change and invalidate our cache | |
setTimeout(function () { | |
var radius = Math.floor(Math.random() * 100 ); | |
document.querySelector("#testDiv").style.width = radius + 'px'; | |
console.log('I should NOT have the correct value of ' + radius + ' (race start): ' + Ext.get('testDiv').getWidth()); | |
setTimeout(function () { | |
console.log('I should have the correct value of ' + radius + ' (race condition end): ' + Ext.get('testDiv').getWidth()); | |
}, 100); | |
}, 1000); | |
} | |
}); | |
</script> | |
</html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment