Skip to content

Commit 8edafd0

Browse files
crisbetothePunderWoman
authored andcommitted
perf(platform-server): speed up resolution of base (#61392)
The `getBaseHref` method is called several times per request and currently queries through the entire document. We can speed it up by taking advantage of the fact that the `<base>` can only be a direct child of the `<head>` and is usually defined towards the beginning. Below are some benchmarks for a "Hello world" app before and after this change. ### Before: ``` Running 60s test @ http://localhost:4202 100 connections with 10 pipelining factor ┌─────────┬────────┬────────┬────────┬────────┬───────────┬──────────┬─────────┐ │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ ├─────────┼────────┼────────┼────────┼────────┼───────────┼──────────┼─────────┤ │ Latency │ 568 ms │ 853 ms │ 901 ms │ 904 ms │ 866.58 ms │ 437.6 ms │ 9915 ms │ └─────────┴────────┴────────┴────────┴────────┴───────────┴──────────┴─────────┘ ┌───────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐ │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Req/Sec │ 490 │ 826 │ 1,006 │ 1,643 │ 1,129.3 │ 234.69 │ 490 │ ├───────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┼─────────┤ │ Bytes/Sec │ 10.4 MB │ 17.4 MB │ 21.3 MB │ 34.7 MB │ 23.9 MB │ 4.96 MB │ 10.3 MB │ └───────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘ Req/Bytes counts sampled once per second. # of samples: 60 69k requests in 60.04s, 1.43 GB read 90 errors (90 timeouts) ``` ### After ``` Running 60s test @ http://localhost:4202 100 connections with 10 pipelining factor ┌─────────┬────────┬────────┬────────┬─────────┬───────────┬───────────┬─────────┐ │ Stat │ 2.5% │ 50% │ 97.5% │ 99% │ Avg │ Stdev │ Max │ ├─────────┼────────┼────────┼────────┼─────────┼───────────┼───────────┼─────────┤ │ Latency │ 471 ms │ 831 ms │ 889 ms │ 1668 ms │ 835.91 ms │ 467.89 ms │ 9720 ms │ └─────────┴────────┴────────┴────────┴─────────┴───────────┴───────────┴─────────┘ ┌───────────┬─────────┬─────────┬─────────┬─────────┬──────────┬────────┬─────────┐ │ Stat │ 1% │ 2.5% │ 50% │ 97.5% │ Avg │ Stdev │ Min │ ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼────────┼─────────┤ │ Req/Sec │ 390 │ 860 │ 1,145 │ 1,572 │ 1,156.77 │ 222.65 │ 390 │ ├───────────┼─────────┼─────────┼─────────┼─────────┼──────────┼────────┼─────────┤ │ Bytes/Sec │ 8.24 MB │ 18.2 MB │ 24.2 MB │ 33.2 MB │ 24.4 MB │ 4.7 MB │ 8.24 MB │ └───────────┴─────────┴─────────┴─────────┴─────────┴──────────┴────────┴─────────┘ Req/Bytes counts sampled once per second. # of samples: 60 71k requests in 60.03s, 1.47 GB read 140 errors (140 timeouts) ``` PR Close #61392
1 parent 11589d4 commit 8edafd0

File tree

2 files changed

+19
-3
lines changed

2 files changed

+19
-3
lines changed

packages/platform-browser/src/browser/browser_adapter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ export class BrowserDomAdapter extends DomAdapter {
8686

8787
let baseElement: HTMLElement | null = null;
8888
function getBaseElementHref(): string | null {
89-
baseElement = baseElement || document.querySelector('base');
89+
baseElement = baseElement || document.head.querySelector('base');
9090
return baseElement ? baseElement.getAttribute('href') : null;
9191
}
9292

packages/platform-server/src/domino_adapter.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,24 @@ export class DominoAdapter extends BrowserDomAdapter {
7979
}
8080

8181
override getBaseHref(doc: Document): string {
82-
// TODO(alxhub): Need relative path logic from BrowserDomAdapter here?
83-
return doc.documentElement!.querySelector('base')?.getAttribute('href') || '';
82+
const length = doc.head.children.length;
83+
84+
// The `<base>` can only be a direct child of `<head>` so we can save some
85+
// execution time by looking through them directly instead of querying for it.
86+
// See: https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/base
87+
// Note that we can't cache the `href` value itself, because this method gets called with a
88+
// different document every time which means that in theory the value can be different too.
89+
for (let i = 0; i < length; i++) {
90+
const child = doc.head.children[i];
91+
92+
// Tag names are always uppercase for HTML nodes.
93+
if (child.tagName === 'BASE') {
94+
// TODO(alxhub): Need relative path logic from BrowserDomAdapter here?
95+
return child.getAttribute('href') || '';
96+
}
97+
}
98+
99+
return '';
84100
}
85101

86102
override dispatchEvent(el: Node, evt: any) {

0 commit comments

Comments
 (0)