Skip to content

Commit

Permalink
perf(trie-router): avoid calling spread operator for `Object.create(n…
Browse files Browse the repository at this point in the history
…ull)` (#3735)

* perf(trie-router): avoid calling spread operator for `Object.create(null)`

This optimization is based on the discussion in the following Pull Request.
Thanks to @EdamAme-x!
#3732

Co-authored-by: EdamAmex <[email protected]>

* perf(trie-router): make some #getHandlerSets parameters optional

* fix(trie-router): fix #getHandlerSets bug

---------

Co-authored-by: EdamAmex <[email protected]>
  • Loading branch information
usualoma and EdamAme-x authored Dec 9, 2024
1 parent 979510f commit 47bb23c
Showing 1 changed file with 18 additions and 25 deletions.
43 changes: 18 additions & 25 deletions src/router/trie-router/node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@ type HandlerParamsSet<T> = HandlerSet<T> & {
params: Record<string, string>
}

const emptyParams = Object.create(null)

export class Node<T> {
#methods: Record<string, HandlerSet<T>>[]

#children: Record<string, Node<T>>
#patterns: Pattern[]
#order: number = 0
#params: Record<string, string> = Object.create(null)
#params: Record<string, string> = emptyParams

constructor(method?: string, handler?: T, children?: Record<string, Node<T>>) {
this.#children = children || Object.create(null)
Expand Down Expand Up @@ -82,7 +84,7 @@ export class Node<T> {
node: Node<T>,
method: string,
nodeParams: Record<string, string>,
params: Record<string, string>
params?: Record<string, string>
): HandlerParamsSet<T>[] {
const handlerSets: HandlerParamsSet<T>[] = []
for (let i = 0, len = node.#methods.length; i < len; i++) {
Expand All @@ -91,23 +93,24 @@ export class Node<T> {
const processedSet: Record<number, boolean> = {}
if (handlerSet !== undefined) {
handlerSet.params = Object.create(null)
for (let i = 0, len = handlerSet.possibleKeys.length; i < len; i++) {
const key = handlerSet.possibleKeys[i]
const processed = processedSet[handlerSet.score]
handlerSet.params[key] =
params[key] && !processed ? params[key] : nodeParams[key] ?? params[key]
processedSet[handlerSet.score] = true
}

handlerSets.push(handlerSet)
if (nodeParams !== emptyParams || (params && params !== emptyParams)) {
for (let i = 0, len = handlerSet.possibleKeys.length; i < len; i++) {
const key = handlerSet.possibleKeys[i]
const processed = processedSet[handlerSet.score]
handlerSet.params[key] =
params?.[key] && !processed ? params[key] : nodeParams[key] ?? params?.[key]
processedSet[handlerSet.score] = true
}
}
}
}
return handlerSets
}

search(method: string, path: string): [[T, Params][]] {
const handlerSets: HandlerParamsSet<T>[] = []
this.#params = Object.create(null)
this.#params = emptyParams

// eslint-disable-next-line @typescript-eslint/no-this-alias
const curNode: Node<T> = this
Expand All @@ -129,35 +132,25 @@ export class Node<T> {
// '/hello/*' => match '/hello'
if (nextNode.#children['*']) {
handlerSets.push(
...this.#getHandlerSets(
nextNode.#children['*'],
method,
node.#params,
Object.create(null)
)
...this.#getHandlerSets(nextNode.#children['*'], method, node.#params)
)
}
handlerSets.push(
...this.#getHandlerSets(nextNode, method, node.#params, Object.create(null))
)
handlerSets.push(...this.#getHandlerSets(nextNode, method, node.#params))
} else {
tempNodes.push(nextNode)
}
}

for (let k = 0, len3 = node.#patterns.length; k < len3; k++) {
const pattern = node.#patterns[k]

const params = { ...node.#params }
const params = node.#params === emptyParams ? {} : { ...node.#params }

// Wildcard
// '/hello/*/foo' => match /hello/bar/foo
if (pattern === '*') {
const astNode = node.#children['*']
if (astNode) {
handlerSets.push(
...this.#getHandlerSets(astNode, method, node.#params, Object.create(null))
)
handlerSets.push(...this.#getHandlerSets(astNode, method, node.#params))
tempNodes.push(astNode)
}
continue
Expand Down

0 comments on commit 47bb23c

Please sign in to comment.