feat(router): hash-cons ComponentInstructions
This commit is contained in:
parent
76e1f863a2
commit
e1a7e0329c
@ -83,6 +83,12 @@ function stringifyAux(instruction: Instruction): string {
|
|||||||
*
|
*
|
||||||
* `ComponentInstructions` is a public API. Instances of `ComponentInstruction` are passed
|
* `ComponentInstructions` is a public API. Instances of `ComponentInstruction` are passed
|
||||||
* to route lifecycle hooks, like {@link CanActivate}.
|
* to route lifecycle hooks, like {@link CanActivate}.
|
||||||
|
*
|
||||||
|
* `ComponentInstruction`s are [https://en.wikipedia.org/wiki/Hash_consing](hash consed). You should
|
||||||
|
* never construct one yourself with "new." Instead, rely on {@link PathRecognizer} to construct
|
||||||
|
* `ComponentInstruction`s.
|
||||||
|
*
|
||||||
|
* You should not modify this object. It should be treated as immutable.
|
||||||
*/
|
*/
|
||||||
export class ComponentInstruction {
|
export class ComponentInstruction {
|
||||||
reuse: boolean = false;
|
reuse: boolean = false;
|
||||||
|
@ -192,6 +192,8 @@ export class PathRecognizer {
|
|||||||
specificity: number;
|
specificity: number;
|
||||||
terminal: boolean = true;
|
terminal: boolean = true;
|
||||||
hash: string;
|
hash: string;
|
||||||
|
private cache: Map<string, ComponentInstruction> = new Map<string, ComponentInstruction>();
|
||||||
|
|
||||||
|
|
||||||
// TODO: cache component instruction instances by params and by ParsedUrl instance
|
// TODO: cache component instruction instances by params and by ParsedUrl instance
|
||||||
|
|
||||||
@ -252,23 +254,26 @@ export class PathRecognizer {
|
|||||||
|
|
||||||
var auxiliary;
|
var auxiliary;
|
||||||
var instruction: ComponentInstruction;
|
var instruction: ComponentInstruction;
|
||||||
|
var urlParams;
|
||||||
|
var allParams;
|
||||||
if (isPresent(currentSegment)) {
|
if (isPresent(currentSegment)) {
|
||||||
// If this is the root component, read query params. Otherwise, read matrix params.
|
// If this is the root component, read query params. Otherwise, read matrix params.
|
||||||
var paramsSegment = beginningSegment instanceof RootUrl ? beginningSegment : currentSegment;
|
var paramsSegment = beginningSegment instanceof RootUrl ? beginningSegment : currentSegment;
|
||||||
|
|
||||||
var allParams = isPresent(paramsSegment.params) ?
|
allParams = isPresent(paramsSegment.params) ?
|
||||||
StringMapWrapper.merge(paramsSegment.params, positionalParams) :
|
StringMapWrapper.merge(paramsSegment.params, positionalParams) :
|
||||||
positionalParams;
|
positionalParams;
|
||||||
|
|
||||||
var urlParams = serializeParams(paramsSegment.params);
|
urlParams = serializeParams(paramsSegment.params);
|
||||||
|
|
||||||
instruction = new ComponentInstruction(urlPath, urlParams, this, allParams);
|
|
||||||
|
|
||||||
auxiliary = currentSegment.auxiliary;
|
auxiliary = currentSegment.auxiliary;
|
||||||
} else {
|
} else {
|
||||||
instruction = new ComponentInstruction(urlPath, [], this, positionalParams);
|
allParams = positionalParams;
|
||||||
auxiliary = [];
|
auxiliary = [];
|
||||||
|
urlParams = [];
|
||||||
}
|
}
|
||||||
|
instruction = this._getInstruction(urlPath, urlParams, this, allParams);
|
||||||
return new PathMatch(instruction, nextSegment, auxiliary);
|
return new PathMatch(instruction, nextSegment, auxiliary);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,6 +294,18 @@ export class PathRecognizer {
|
|||||||
var nonPositionalParams = paramTokens.getUnused();
|
var nonPositionalParams = paramTokens.getUnused();
|
||||||
var urlParams = serializeParams(nonPositionalParams);
|
var urlParams = serializeParams(nonPositionalParams);
|
||||||
|
|
||||||
return new ComponentInstruction(urlPath, urlParams, this, params);
|
return this._getInstruction(urlPath, urlParams, this, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
private _getInstruction(urlPath: string, urlParams: List<string>, _recognizer: PathRecognizer,
|
||||||
|
params: StringMap<string, any>): ComponentInstruction {
|
||||||
|
var hashKey = urlPath + '?' + urlParams.join('?');
|
||||||
|
if (this.cache.has(hashKey)) {
|
||||||
|
return this.cache.get(hashKey);
|
||||||
|
}
|
||||||
|
var instruction = new ComponentInstruction(urlPath, urlParams, _recognizer, params);
|
||||||
|
this.cache.set(hashKey, instruction);
|
||||||
|
|
||||||
|
return instruction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,17 @@ export function main() {
|
|||||||
.toThrowError(`Path "hi//there" contains "//" which is not allowed in a route config.`);
|
.toThrowError(`Path "hi//there" contains "//" which is not allowed in a route config.`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return the same instruction instance when recognizing the same path', () => {
|
||||||
|
var rec = new PathRecognizer('/one', mockRouteHandler);
|
||||||
|
|
||||||
|
var one = new Url('one', null, null, {});
|
||||||
|
|
||||||
|
var firstMatch = rec.recognize(one);
|
||||||
|
var secondMatch = rec.recognize(one);
|
||||||
|
|
||||||
|
expect(firstMatch.instruction).toBe(secondMatch.instruction);
|
||||||
|
});
|
||||||
|
|
||||||
describe('querystring params', () => {
|
describe('querystring params', () => {
|
||||||
it('should parse querystring params so long as the recognizer is a root', () => {
|
it('should parse querystring params so long as the recognizer is a root', () => {
|
||||||
var rec = new PathRecognizer('/hello/there', mockRouteHandler);
|
var rec = new PathRecognizer('/hello/there', mockRouteHandler);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user