Skip to content

Commit e9b488f

Browse files
Add caching to namespace lookup to drastically improve speed during resolveAll (30x in benchmarks)
1 parent 1982e52 commit e9b488f

File tree

1 file changed

+54
-15
lines changed

1 file changed

+54
-15
lines changed

src/namespace.js

Lines changed: 54 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -108,10 +108,27 @@ function Namespace(name, options) {
108108
* @private
109109
*/
110110
this._nestedArray = null;
111+
112+
/**
113+
* Cache lookup calls for any objects contains anywhere under this namespace.
114+
* This drastically speeds up resolve for large cross-linked protos where the same
115+
* types are looked up repeatedly.
116+
* @type {Object.<string,ReflectionObject|null>}
117+
* @private
118+
*/
119+
this._lookupCache = {};
111120
}
112121

113122
function clearCache(namespace) {
114123
namespace._nestedArray = null;
124+
namespace._lookupCache = {};
125+
126+
// Also clear parent caches, since they include nested lookups.
127+
var parent = namespace.parent;
128+
while(parent) {
129+
parent._lookupCache = {};
130+
parent = parent.parent;
131+
}
115132
return namespace;
116133
}
117134

@@ -341,7 +358,6 @@ Namespace.prototype._resolveFeaturesRecursive = function _resolveFeaturesRecursi
341358
* @returns {ReflectionObject|null} Looked up object or `null` if none could be found
342359
*/
343360
Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChecked) {
344-
345361
/* istanbul ignore next */
346362
if (typeof filterTypes === "boolean") {
347363
parentAlreadyChecked = filterTypes;
@@ -360,25 +376,48 @@ Namespace.prototype.lookup = function lookup(path, filterTypes, parentAlreadyChe
360376
if (path[0] === "")
361377
return this.root.lookup(path.slice(1), filterTypes);
362378

363-
// Test if the first part matches any nested object, and if so, traverse if path contains more
364-
var found = this.get(path[0]);
365-
if (found) {
366-
if (path.length === 1) {
367-
if (!filterTypes || filterTypes.indexOf(found.constructor) > -1)
368-
return found;
369-
} else if (found instanceof Namespace && (found = found.lookup(path.slice(1), filterTypes, true)))
370-
return found;
371-
372-
// Otherwise try each nested namespace
373-
} else
374-
for (var i = 0; i < this.nestedArray.length; ++i)
375-
if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i].lookup(path, filterTypes, true)))
376-
return found;
379+
var found = this._lookupImpl(path);
380+
if (found && (!filterTypes || filterTypes.indexOf(found.constructor) > -1)) {
381+
return found;
382+
}
377383

378384
// If there hasn't been a match, try again at the parent
379385
if (this.parent === null || parentAlreadyChecked)
380386
return null;
381387
return this.parent.lookup(path, filterTypes);
388+
}
389+
390+
/**
391+
* Internal helper for lookup that handles searching just at this namespace and below along with caching.
392+
* @param {string[]} path Path to look up
393+
* @returns {ReflectionObject|null} Looked up object or `null` if none could be found
394+
* @private
395+
*/
396+
Namespace.prototype._lookupImpl = function lookup(path) {
397+
var flatPath = path.join(".");
398+
if(this._lookupCache.hasOwnProperty(flatPath)) {
399+
return this._lookupCache[flatPath];
400+
} else {
401+
// Test if the first part matches any nested object, and if so, traverse if path contains more
402+
var found = this.get(path[0]);
403+
var exact = null;
404+
if (found) {
405+
if (path.length === 1) {
406+
exact = found;
407+
} else if (found instanceof Namespace && (found = found._lookupImpl(path.slice(1))))
408+
exact = found;
409+
410+
// Otherwise try each nested namespace
411+
} else {
412+
for (var i = 0; i < this.nestedArray.length; ++i)
413+
if (this._nestedArray[i] instanceof Namespace && (found = this._nestedArray[i]._lookupImpl(path)))
414+
exact = found;
415+
}
416+
417+
// Set this even when null, so that when we walk up the tree we can quickly bail on repeated checks back down.
418+
this._lookupCache[flatPath] = exact;
419+
return exact;
420+
}
382421
};
383422

384423
/**

0 commit comments

Comments
 (0)