Skip to content

Commit

Permalink
Improve InternalModel (2x - 3x) allocation cost.
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanpenner committed Aug 12, 2015
1 parent 1f866da commit b6109d0
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 13 deletions.
17 changes: 17 additions & 0 deletions packages/ember-data/lib/system/empty-object.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// This exists because `Object.create(null)` is absurdly slow compared
// to `new EmptyObject()`. In either case, you want a null prototype
// when you're treating the object instances as arbitrary dictionaries
// and don't want your keys colliding with build-in methods on the
// default object prototype.
var proto = Object.create(null, {
// without this, we will always still end up with (new
// EmptyObject()).constructor === Object
constructor: {
value: undefined,
enumerable: false,
writable: true
}
});

export default function EmptyObject() {}
EmptyObject.prototype = proto;
30 changes: 17 additions & 13 deletions packages/ember-data/lib/system/model/internal-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@ import merge from "ember-data/system/merge";
import RootState from "ember-data/system/model/states";
import Relationships from "ember-data/system/relationships/state/create";
import Snapshot from "ember-data/system/snapshot";
import EmptyObject from "ember-data/system/empty-object";

var Promise = Ember.RSVP.Promise;
var get = Ember.get;
var set = Ember.set;

var _extractPivotNameCache = Object.create(null);
var _splitOnDotCache = Object.create(null);
var _extractPivotNameCache = new EmberObject();
var _splitOnDotCache = new EmberObject();

function splitOnDot(name) {
return _splitOnDotCache[name] || (
Expand All @@ -28,6 +29,7 @@ function retrieveFromCurrentState(key) {
};
}

var guid = 0;
/**
`InternalModel` is the Model class that we use internally inside Ember Data to represent models.
Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class.
Expand All @@ -43,23 +45,25 @@ function retrieveFromCurrentState(key) {
@class InternalModel
*/

export default function InternalModel(type, id, store, container, data) {
this.type = type;
this.id = id;
this.store = store;
this.container = container;
this._data = data || Object.create(null);
this._data = data || new EmptyObject();
this.modelName = type.modelName;
this.dataHasInitialized = false;
//Look into making this lazy
this._deferredTriggers = [];
this._attributes = Object.create(null);
this._inFlightAttributes = Object.create(null);
this._attributes = new EmptyObject();
this._inFlightAttributes = new EmptyObject();
this._relationships = new Relationships(this);
this.currentState = RootState.empty;
this.isReloading = false;
this.isError = false;
this.error = null;
this[Ember.GUID_KEY] = guid++ + 'internal-model';
/*
implicit relationships are relationship which have not been declared but the inverse side exists on
another record somewhere
Expand Down Expand Up @@ -87,7 +91,7 @@ export default function InternalModel(type, id, store, container, data) {
would have a implicit post relationship in order to be do things like remove ourselves from the post
when we are deleted
*/
this._implicitRelationships = Object.create(null);
this._implicitRelationships = new EmptyObject();
}

InternalModel.prototype = {
Expand Down Expand Up @@ -263,7 +267,7 @@ InternalModel.prototype = {

flushChangedAttributes: function() {
this._inFlightAttributes = this._attributes;
this._attributes = Object.create(null);
this._attributes = new EmptyObject();
},

/**
Expand Down Expand Up @@ -326,10 +330,10 @@ InternalModel.prototype = {
rollbackAttributes: function() {
var dirtyKeys = Object.keys(this._attributes);

this._attributes = Object.create(null);
this._attributes = new EmptyObject();

if (get(this, 'isError')) {
this._inFlightAttributes = Object.create(null);
this._inFlightAttributes = new EmptyObject();
this.didCleanError();
}

Expand All @@ -346,7 +350,7 @@ InternalModel.prototype = {
}

if (this.isValid()) {
this._inFlightAttributes = Object.create(null);
this._inFlightAttributes = new EmptyObject();
}

this.send('rolledBack');
Expand Down Expand Up @@ -585,7 +589,7 @@ InternalModel.prototype = {
merge(this._data, data);
}

this._inFlightAttributes = Object.create(null);
this._inFlightAttributes = new EmptyObject();

this.send('didCommit');
this.updateRecordArraysLater();
Expand Down Expand Up @@ -656,7 +660,7 @@ InternalModel.prototype = {
this._attributes[keys[i]] = this._inFlightAttributes[keys[i]];
}
}
this._inFlightAttributes = Object.create(null);
this._inFlightAttributes = new EmptyObject();
},

/**
Expand Down Expand Up @@ -708,7 +712,7 @@ InternalModel.prototype = {
var keys = Object.keys(updates);
var length = keys.length;

original = merge(Object.create(null), this._data);
original = merge(new EmptyObject(), this._data);
original = merge(original, this._inFlightAttributes);

for (i = 0; i < length; i++) {
Expand Down

0 comments on commit b6109d0

Please sign in to comment.