Skip to content

Commit

Permalink
Back port from 2.1.0-beta1:
Browse files Browse the repository at this point in the history
emberjs#3641 Improve InternalModel (2x - 3x faster)
emberjs#3649 Empty object
  • Loading branch information
jnfisher authored and Alan committed Sep 3, 2015
1 parent a476f3f commit 750f5f3
Show file tree
Hide file tree
Showing 13 changed files with 67 additions and 40 deletions.
4 changes: 2 additions & 2 deletions packages/ember-data/lib/adapters/rest-adapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ import {
import {
MapWithDefault
} from "ember-data/system/map";
import EmptyObject from "ember-data/system/empty-object";
import ArrayPolyfills from 'ember-data/ext/ember/array';

var get = Ember.get;
var set = Ember.set;
var forEach = ArrayPolyfills.forEach;

import {
create,
keysFunc
} from 'ember-data/system/object-polyfills';

Expand Down Expand Up @@ -1042,7 +1042,7 @@ var RestAdapter = Adapter.extend(BuildURLMixin, {
});

function parseResponseHeaders(headerStr) {
var headers = create(null);
var headers = new EmptyObject();
if (!headerStr) { return headers; }

var headerPairs = headerStr.split('\u000d\u000a');
Expand Down
6 changes: 2 additions & 4 deletions packages/ember-data/lib/system/clone-null.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import {
create
} from 'ember-data/system/object-polyfills';
import EmptyObject from "ember-data/system/empty-object";

export default function cloneNull(source) {
var clone = create(null);
var clone = new EmptyObject();
for (var key in source) {
clone[key] = source[key];
}
Expand Down
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;
6 changes: 4 additions & 2 deletions packages/ember-data/lib/system/model/internal-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ 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";

import ArrayPolyfills from 'ember-data/ext/ember/array';

import {
Expand All @@ -16,8 +18,8 @@ var set = Ember.set;
var forEach = ArrayPolyfills.forEach;
var map = ArrayPolyfills.map;

var _extractPivotNameCache = create(null);
var _splitOnDotCache = create(null);
var _extractPivotNameCache = new EmptyObject();
var _splitOnDotCache = new EmptyObject();

function splitOnDot(name) {
return _splitOnDotCache[name] || (
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-data/lib/system/model/model.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { PromiseObject } from "ember-data/system/promise-proxies";
import Errors from "ember-data/system/model/errors";
import EmptyObject from "ember-data/system/empty-object";
import ArrayPolyfills from 'ember-data/ext/ember/array';

import {
create,
keysFunc
} from 'ember-data/system/object-polyfills';

Expand Down Expand Up @@ -674,7 +674,7 @@ var Model = Ember.Object.extend(Ember.Evented, {
var currentData = get(this._internalModel, '_attributes');
var inFlightData = get(this._internalModel, '_inFlightAttributes');
var newData = merge(copy(inFlightData), currentData);
var diffData = create(null);
var diffData = new EmptyObject();

var newDataKeys = keysFunc(newData);

Expand Down
4 changes: 3 additions & 1 deletion packages/ember-data/lib/system/model/states.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import EmptyObject from "ember-data/system/empty-object";

import {
create,
keysFunc
Expand Down Expand Up @@ -360,7 +362,7 @@ var DirtyState = {
},

exit: function(internalModel) {
internalModel._inFlightAttributes = create(null);
internalModel._inFlightAttributes = new EmptyObject();
}
}
};
Expand Down
7 changes: 2 additions & 5 deletions packages/ember-data/lib/system/relationships/ext.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,9 @@ import {
Map,
MapWithDefault
} from "ember-data/system/map";
import EmptyObject from "ember-data/system/empty-object";
import ArrayPolyfills from 'ember-data/ext/ember/array';

import {
create
} from 'ember-data/system/object-polyfills';

var get = Ember.get;
var filter = ArrayPolyfills.filter;

Expand Down Expand Up @@ -191,7 +188,7 @@ Model.reopenClass({
},

inverseMap: Ember.computed(function() {
return create(null);
return new EmptyObject();
}),

/**
Expand Down
7 changes: 2 additions & 5 deletions packages/ember-data/lib/system/relationships/state/create.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import ManyRelationship from "ember-data/system/relationships/state/has-many";
import BelongsToRelationship from "ember-data/system/relationships/state/belongs-to";

import {
create
} from 'ember-data/system/object-polyfills';
import EmptyObject from "ember-data/system/empty-object";

var get = Ember.get;

Expand All @@ -24,7 +21,7 @@ var createRelationshipFor = function(record, relationshipMeta, store) {

var Relationships = function(record) {
this.record = record;
this.initializedRelationships = create(null);
this.initializedRelationships = new EmptyObject();
};

Relationships.prototype.has = function(key) {
Expand Down
15 changes: 8 additions & 7 deletions packages/ember-data/lib/system/snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@

var get = Ember.get;
import {
create,
keysFunc
} from 'ember-data/system/object-polyfills';

import EmptyObject from "ember-data/system/empty-object";

/**
@class Snapshot
@namespace DS
Expand All @@ -16,11 +17,11 @@ import {
@param {DS.Model} internalModel The model to create a snapshot from
*/
function Snapshot(internalModel) {
this._attributes = create(null);
this._belongsToRelationships = create(null);
this._belongsToIds = create(null);
this._hasManyRelationships = create(null);
this._hasManyIds = create(null);
this._attributes = new EmptyObject();
this._belongsToRelationships = new EmptyObject();
this._belongsToIds = new EmptyObject();
this._hasManyRelationships = new EmptyObject();
this._hasManyIds = new EmptyObject();

var record = internalModel.getRecord();
this.record = record;
Expand Down Expand Up @@ -172,7 +173,7 @@ Snapshot.prototype = {
@return {Object} All changed attributes of the current snapshot
*/
changedAttributes: function() {
let changedAttributes = create(null);
let changedAttributes = new EmptyObject();
let changedAttributeKeys = keysFunc(this._changedAttributes);

for (let i=0, length = changedAttributeKeys.length; i < length; i++) {
Expand Down
11 changes: 6 additions & 5 deletions packages/ember-data/lib/system/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ import InternalModel from "ember-data/system/model/internal-model";
import ArrayPolyfills from 'ember-data/ext/ember/array';

import {
create,
keysFunc
} from 'ember-data/system/object-polyfills';

import EmptyObject from "ember-data/system/empty-object";

var Backburner = Ember._Backburner || Ember.Backburner || Ember.__loader.require('backburner')['default'] || Ember.__loader.require('backburner')['Backburner'];


Expand Down Expand Up @@ -329,7 +330,7 @@ Store = Service.extend({
createRecord: function(modelName, inputProperties) {
Ember.assert('Passing classes to store methods has been removed. Please pass a dasherized string instead of '+ Ember.inspect(modelName), typeof modelName === 'string');
var typeClass = this.modelFor(modelName);
var properties = copy(inputProperties) || create(null);
var properties = copy(inputProperties) || new EmptyObject();

// If the passed properties do not include a primary key,
// give the adapter an opportunity to generate one. Typically,
Expand Down Expand Up @@ -1338,7 +1339,7 @@ Store = Service.extend({
record.destroy(); // maybe within unloadRecord
}

typeMap.metadata = create(null);
typeMap.metadata = new EmptyObject();
}

function byType(entry) {
Expand Down Expand Up @@ -1689,9 +1690,9 @@ Store = Service.extend({
if (typeMap) { return typeMap; }

typeMap = {
idToRecord: create(null),
idToRecord: new EmptyObject(),
records: [],
metadata: create(null),
metadata: new EmptyObject(),
type: typeClass
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import Ember from 'ember';

import {
create,
keysFunc
} from 'ember-data/system/object-polyfills';

import EmptyObject from "ember-data/system/empty-object";

/**
* The `ContainerInstanceCache` serves as a lazy cache for looking up
* instances of serializers and adapters. It has some additional logic for
Expand All @@ -25,10 +26,10 @@ import {
*/
function ContainerInstanceCache(container) {
this._container = container;
this._cache = create(null);
this._cache = new EmptyObject();
}

ContainerInstanceCache.prototype = create(null);
ContainerInstanceCache.prototype = new EmptyObject();

Ember.merge(ContainerInstanceCache.prototype, {
get: function(type, preferredKey, fallbacks) {
Expand Down
4 changes: 2 additions & 2 deletions packages/ember-data/tests/integration/store-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,8 +149,8 @@ test("destroying the store correctly cleans everything up", function() {
filterdPeople = store.filter('person', function() { return true; });
});

var filterdPeopleWillDestroy = tap(filterdPeople.content, 'willDestroy');
var adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.content, 'willDestroy');
var filterdPeopleWillDestroy = tap(filterdPeople.get('content'), 'willDestroy');
var adapterPopulatedPeopleWillDestroy = tap(adapterPopulatedPeople.get('content'), 'willDestroy');

run(function() {
store.findRecord('person', 2);
Expand Down
15 changes: 13 additions & 2 deletions packages/ember-data/tests/unit/model-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -227,12 +227,23 @@ test("changedAttributes() return correct values", function() {
equal(keysFunc(mascot.changedAttributes()).length, 0, 'after rollback attributes there are no changes');
});

function toObj(obj) {
// https://github.com/jquery/qunit/issues/851
var result = Object.create(null);
for (var key in obj) {
result[key] = obj[key];
}
return result;
}

test("changedAttributes() works while the record is being saved", function() {
expect(1);
var cat;
var adapter = DS.Adapter.extend({
createRecord(store, model, snapshot) {
deepEqual(cat.changedAttributes(), { name: [undefined, 'Argon'], likes: [undefined, 'Cheese'] });
deepEqual(toObj(cat.changedAttributes()), {
name: [undefined, 'Argon'],
likes: [undefined, 'Cheese'] });
return {};
}
});
Expand All @@ -259,7 +270,7 @@ test("changedAttributes() works while the record is being updated", function() {
var cat;
var adapter = DS.Adapter.extend({
updateRecord(store, model, snapshot) {
deepEqual(cat.changedAttributes(), { name: ['Argon', 'Helia'], likes: ['Cheese', 'Mussels'] });
deepEqual(toObj(cat.changedAttributes()), { name: ['Argon', 'Helia'], likes: ['Cheese', 'Mussels'] });
return { id: '1', type: 'mascot' };
}
});
Expand Down

0 comments on commit 750f5f3

Please sign in to comment.