diff --git a/lib/mongo/ObserveMultiplex.js b/lib/mongo/ObserveMultiplex.js index 7a086974..36e889bc 100644 --- a/lib/mongo/ObserveMultiplex.js +++ b/lib/mongo/ObserveMultiplex.js @@ -189,13 +189,9 @@ _.extend(ObserveMultiplexer.prototype, { if (!self._handles) return; // First, apply the change to the cache. - // XXX We could make applyChange callbacks promise not to hang on to any - // state from their arguments (assuming that their supplied callbacks - // don't) and skip this clone. Currently 'changed' hangs on to state - // though. self._cache.applyChange[callbackName].apply( null, - EJSON.clone(args) + args ); // If we haven't finished the initial adds, then we should only be getting @@ -221,7 +217,7 @@ _.extend(ObserveMultiplexer.prototype, { // We silence out removed exceptions if (callback === 'removed') { try { - callback.apply(null, EJSON.clone(args)); + callback.apply(null, handle.nonMutatingCallbacks ? args : EJSON.clone(args)); } catch (e) { // Supressing `removed non-existent exceptions` if (!isRemovedNonExistent(e)) { @@ -229,7 +225,8 @@ _.extend(ObserveMultiplexer.prototype, { } } } else { - callback && callback.apply(null, EJSON.clone(args)); + callback && callback.apply(null, + handle.nonMutatingCallbacks ? args : EJSON.clone(args)); } }); }); @@ -249,8 +246,8 @@ _.extend(ObserveMultiplexer.prototype, { self._cache.docs.forEach(function(doc, id) { if (!_.has(self._handles, handle._id)) throw Error('handle got removed before sending initial adds!'); - var fields = EJSON.clone(doc); - delete fields._id; + const { _id, ...fields } = handle.nonMutatingCallbacks ? doc + : EJSON.clone(doc); if (self._ordered) add(id, fields, null); // we're going in order, so add at end else add(id, fields); @@ -259,7 +256,9 @@ _.extend(ObserveMultiplexer.prototype, { }); var nextObserveHandleId = 1; -export function ObserveHandle(multiplexer, callbacks) { + +// When the callbacks do not mutate the arguments, we can skip a lot of data clones +export function ObserveHandle(multiplexer, callbacks, nonMutatingCallbacks = false) { var self = this; // The end user is only supposed to call stop(). The other fields are // accessible to the multiplexer, though. @@ -279,6 +278,7 @@ export function ObserveHandle(multiplexer, callbacks) { }); self._stopped = false; self._id = nextObserveHandleId++; + self.nonMutatingCallbacks = nonMutatingCallbacks; } ObserveHandle.prototype.stop = function() {