angular-restmod
angular-restmod copied to clipboard
Performance of $scope on large datasets
I'm doing some heap debugging in Chrome... I noticed one of the largest retained constructors was a restmod collection of a few hundred objects.
Specifically, the retained size is in the $scope property.
I wanted to start a discussion around this...
- Is
$scope
needed? If so, what is its purpose? - Is
$scope
being properly garbage collected within the restmod library? - Could I be using restmod collections in a way that prevents garbage collection?
Could you share some information about your model structure?
Each record/collection has a $scope
property that holds the parent scope.
The first thing that comes to mind is that you are calling $search
on a collection and then $search
again on the resulting collection and then $search
again on the result and so on. Each time you call $search
on a given collection a new child collection is created and its $scope
property is assigned the initial collection, preventing the GC from collecting the parent collection. For example, if you call test = Model.$seach().$seach().$seach().$seach().$seach().$seach()
you will be left with 5 referenced collections (non collectable) and test.$scope
will show a bigger than usual heap size.
But in this example, if you set test = null;
then then the referenced collections can be garbage collected, correct?
Roughly, my model configuration is as follows
- Trip hasMany points
- Point hasOne sensorData
- Point hasOne wheelData
- Trips can have anywhere from 100 - 10,000 points.
- Point model has many filtering methods that use
$asList()
angular
.module('SPModels')
.factory('Trip', function(restmod) {
return restmod.model('/trips').mix({
$config: {
primaryKey: 'tripId'
},
name: '',
points: {
hasMany: 'Point',
path: 'points',
inverseOf: 'trip'
}
});
});
angular
.module('SPModels')
.factory('Point', function(restmod) {
return restmod.model('/points').mix({
$config: {
primaryKey: 'pointId'
},
location: {
decode: 'DecodeGeoJSONPoint'
},
sensorData: {
hasOne: 'SensorData',
inverseOf: 'point'
},
wheelData: {
hasOne: 'WheelData',
inverseOf: 'point'
},
trip: {
belongsTo: 'Trip'
},
$extend: {
List: {
sampleBy: function(sampleAmt) {
sampleAmt = sampleAmt || 10;
return this.$asList(function(_things) {
return _things.slice(-sampleAmt);
});
}
}
}
});
});
angular
.module('SPModels')
.factory('WheelData', function(restmod) {
return restmod.model(null).mix({
point: {
belongsTo: 'Point'
},
speed: {
init: 0,
decode: 'DecodeNumber'
},
totalOdometer: {
init: 0,
decode: 'DecodeNumber'
},
tripOdometer: {
init: 0,
decode: 'DecodeNumber'
}
});
});
angular
.module('SPModels')
.factory('SensorData', function(restmod) {
return restmod.model(null).mix({
point: {
belongsTo: 'Point'
}
});
});
And some example controller code is below:
// get trips
$scope.trips = Trip.$search();
// active trip, and fetch its points
$scope.activate = function(trip) {
$scope.activeTrip = trip;
$scope.activeTrip.points.$fetch();
};
// get last 10 points from active trip
$scope.sample = function() {
$scope.sampled = $scope.activeTrip.points.sampleLast(10);
}
Any suggestions here?
Maybe you could check how many levels of nested scopes (and their types/contents) are held by the offending object? Just to check if the problem is some unnecessary collection chaining?