mirror of
https://github.com/meteor/meteor.git
synced 2026-05-02 03:01:46 -04:00
introduce Meteor.deps.ContextSet, use in Session
This commit is contained in:
42
packages/deps/deps-utils.js
Normal file
42
packages/deps/deps-utils.js
Normal file
@@ -0,0 +1,42 @@
|
||||
(function () {
|
||||
|
||||
// Constructor for an empty ContextSet.
|
||||
var ContextSet = function () {
|
||||
this._contextsById = {};
|
||||
};
|
||||
|
||||
// Adds the Context `ctx` to the set (if it is
|
||||
// not already present). The Context will only
|
||||
// remain in the set as long as it has not been
|
||||
// invalidated.
|
||||
// Returns true if the context was newly added.
|
||||
ContextSet.prototype.add = function (ctx) {
|
||||
var self = this;
|
||||
if (ctx && ! (ctx.id in self._contextsById)) {
|
||||
self._contextsById[ctx.id] = ctx;
|
||||
ctx.on_invalidate(function () {
|
||||
delete self._contextsById[ctx.id];
|
||||
});
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
// Invalidate all Contexts in the set and remove
|
||||
// them from the set.
|
||||
ContextSet.prototype.invalidateAll = function () {
|
||||
var self = this;
|
||||
for (var id in self._contextsById)
|
||||
self._contextsById[id].invalidate();
|
||||
};
|
||||
|
||||
// Returns true if there are no Contexts in this set.
|
||||
ContextSet.prototype.isEmpty = function () {
|
||||
var self = this;
|
||||
for(var id in self._contextsById)
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
|
||||
Meteor.deps.ContextSet = ContextSet;
|
||||
})();
|
||||
@@ -9,5 +9,5 @@ Package.on_use(function (api, where) {
|
||||
where = where || ['client', 'server'];
|
||||
|
||||
api.use('underscore', where);
|
||||
api.add_files('deps.js', where);
|
||||
api.add_files(['deps.js', 'deps-utils.js'], where);
|
||||
});
|
||||
|
||||
@@ -1,31 +1,9 @@
|
||||
// XXX could use some tests
|
||||
|
||||
Session = _.extend({}, {
|
||||
keys: {},
|
||||
key_deps: {}, // key -> context id -> context
|
||||
key_value_deps: {}, // key -> value -> context id -> context
|
||||
|
||||
// XXX remove debugging method (or improve it, but anyway, don't
|
||||
// ship it in production)
|
||||
dump_state: function () {
|
||||
var self = this;
|
||||
console.log("=== Session state ===");
|
||||
for (var key in self.key_deps) {
|
||||
var ids = _.keys(self.key_deps[key]);
|
||||
if (!ids.length)
|
||||
continue;
|
||||
console.log(key + ": " + _.reject(ids, function (x) {return x === "_once"}).join(' '));
|
||||
}
|
||||
|
||||
for (var key in self.key_value_deps) {
|
||||
for (var value in self.key_value_deps[key]) {
|
||||
var ids = _.keys(self.key_value_deps[key][value]);
|
||||
if (!ids.length)
|
||||
continue;
|
||||
console.log(key + "(" + value + "): " + _.reject(ids, function (x) {return x === "_once";}).join(' '));
|
||||
}
|
||||
}
|
||||
},
|
||||
keys: {}, // key -> value
|
||||
key_deps: {}, // key -> ContextSet
|
||||
key_value_deps: {}, // key -> value -> ContextSet
|
||||
|
||||
set: function (key, value) {
|
||||
var self = this;
|
||||
@@ -35,30 +13,24 @@ Session = _.extend({}, {
|
||||
return;
|
||||
self.keys[key] = value;
|
||||
|
||||
var invalidate = function (map) {
|
||||
if (map)
|
||||
for (var id in map)
|
||||
map[id].invalidate();
|
||||
var invalidateAll = function (set) {
|
||||
set && set.invalidateAll();
|
||||
};
|
||||
|
||||
self._ensureKey(key);
|
||||
invalidate(self.key_deps[key]);
|
||||
invalidate(self.key_value_deps[key][old_value]);
|
||||
invalidate(self.key_value_deps[key][value]);
|
||||
invalidateAll(self.key_deps[key]);
|
||||
if (self.key_value_deps[key]) {
|
||||
invalidateAll(self.key_value_deps[key][old_value]);
|
||||
invalidateAll(self.key_value_deps[key][value]);
|
||||
}
|
||||
},
|
||||
|
||||
get: function (key) {
|
||||
var self = this;
|
||||
var context = Meteor.deps.Context.current;
|
||||
self._ensureKey(key);
|
||||
|
||||
if (context && !(context.id in self.key_deps[key])) {
|
||||
self.key_deps[key][context.id] = context;
|
||||
context.on_invalidate(function () {
|
||||
delete self.key_deps[key][context.id];
|
||||
});
|
||||
if (context) {
|
||||
self._ensureKey(key);
|
||||
self.key_deps[key].add(context);
|
||||
}
|
||||
|
||||
return self.keys[key];
|
||||
},
|
||||
|
||||
@@ -74,19 +46,17 @@ Session = _.extend({}, {
|
||||
|
||||
if (context) {
|
||||
self._ensureKey(key);
|
||||
|
||||
if (!(value in self.key_value_deps[key]))
|
||||
self.key_value_deps[key][value] = {};
|
||||
self.key_value_deps[key][value] = new Meteor.deps.ContextSet;
|
||||
|
||||
if (!(context.id in self.key_value_deps[key][value])) {
|
||||
self.key_value_deps[key][value][context.id] = context;
|
||||
var isNew = self.key_value_deps[key][value].add(context);
|
||||
if (isNew) {
|
||||
context.on_invalidate(function () {
|
||||
delete self.key_value_deps[key][value][context.id];
|
||||
|
||||
// clean up [key][value] if it's now empty, so we don't use
|
||||
// O(n) memory for n = values seen ever
|
||||
for (var x in self.key_value_deps[key][value])
|
||||
return;
|
||||
delete self.key_value_deps[key][value];
|
||||
if (self.key_value_deps[key][value].isEmpty())
|
||||
delete self.key_value_deps[key][value];
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -97,8 +67,8 @@ Session = _.extend({}, {
|
||||
_ensureKey: function (key) {
|
||||
var self = this;
|
||||
if (!(key in self.key_deps)) {
|
||||
self.key_deps[key] = {};
|
||||
self.key_value_deps[key] = {};
|
||||
self.key_deps[key] = new Meteor.deps.ContextSet;
|
||||
self.key_value_deps[key] = new Meteor.deps.ContextSet;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user