Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Property compute is expensive - with shortcut
import Ember from 'ember';
var fib = function(n){
switch(n){
case 0: return 0;
case 1: return 1;
default: return fib(n-1) + fib(n-2);
}
};
/*
* Whenever a properties computed dependencies change, the entire tree will update.
* computedGate is exactly the same as Ember.computed except that if the
* result of the computed doesnt change, none of the dependent properties will recompute.
*/
var computedGateCount = 1;
var computedGate = function() {
var computeds = Array.from(arguments);
var fn = computeds.pop();
var propName = '__computedGate' + (++computedGateCount);
var observerPropName = propName + 'Observer';
var args = computeds.slice(0);
var computedGateObserver = function computedGateObserver() {
var lastValue = this.cacheFor(propName);
var newValue = fn.apply(this, arguments);
if (newValue !== lastValue) {
this.set(propName, newValue);
}
};
args.push(computedGateObserver);
return Ember.computed(propName, function() {
if (!this[observerPropName]) {
var mixin = {};
mixin[observerPropName] = Ember.observer.apply(this, args);
Ember.mixin(this, mixin);
args[args.length - 1].call(this);
}
return this.get(propName);
});
}
var ItemModel = Ember.Object.extend({
someProperty: Ember.computed('index', 'root.clock', 'root.computationCost', function(){
return fib(Math.floor(this.get('root.computationCost'))) + this.get('root.clock') + this.get('index');
}),
});
export default Ember.Controller.extend({
appname: 'Ember Twiddle',
requestedItemCount: 1,
refreshRate: 10,
enableIncreasingItems: false,
computationCost: 0,
refreshDelay: Ember.computed('refreshRate', function(){
if (this.clockTimeout){
Ember.run.cancel(this.clockTimeout);
this.clockTimeout = null;
}
var refreshRate = this.get('refreshRate');
var refreshDelay = 1000 / refreshRate;
if (refreshRate != 0){
this.updateClock(refreshDelay);
}
return refreshDelay;
}),
initClock: Ember.on('init', function(){
this.set('startTime', (new Date).getTime());
this.updateClock();
}),
clockMs: Ember.computed('startTime', function(){
var startTime = this.get('startTime');
var currentTime = (new Date).getTime();
return currentTime - startTime;
}),
clock: computedGate('clockMs', function(){
return Math.floor(this.get('clockMs') / 1000);
}),
updateClock: function(refreshDelay){
this.notifyPropertyChange('clockMs');
this.clockTimeout = Ember.run.later(this, function(){
this.updateClock();
}, refreshDelay);
},
itemCount: Ember.computed('clock', 'requestedItemCount', 'enableIncreasingItems', function(){
if (this.get('enableIncreasingItems')){
return Math.floor(this.get('clock') / 20) * 1;
}
return this.get('requestedItemCount');
}),
items: Ember.computed('itemCount', function(){
var result = Ember.A([]);
for (var i = 0; i < this.get('itemCount'); i++){
result.push(ItemModel.create({root: this, index: i}));
}
return result;
}),
});
<h1>Welcome to {{appName}}</h1>
<br>
<br>
Clock: {{clock}}
<br>
RefreshRate: {{refreshRate}} times / sec <br />
RefreshDelay: {{input type='range' min=0 max=100 step=1 value=refreshRate}} {{refreshDelay}} ms <br />
requestedItemCount: {{input type='range' min=0 max=100 step=1 value=requestedItemCount}} {{requestedItemCount}} <br />
computationCost: {{input type='range' min=0 max=100 step=1 value=computationCost}} {{computationCost}} <br />
Enable Increasing Items: {{input type='checkbox' checked=enableIncreasingItems}}<br />
<br>
{{#each items as |item|}}
<span>{{item.index}} - {{item.someProperty}}</span>
{{/each}}
<br>
{
"version": "0.10.6",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.9.0",
"ember-data": "2.9.0",
"ember-template-compiler": "2.9.0",
"ember-testing": "2.9.0"
},
"addons": {}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment