mirror of
https://github.com/denoland/deno.git
synced 2024-12-23 15:49:44 -05:00
perf(ext/headers): optimize headers iterable (#20155)
This PR makes more optimizations to headers iterable by removing `ObjectEntries` which was consistently prominent in the flame graph when benchmarking an express server. **this PR** ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.36.1 (x86_64-unknown-linux-gnu) benchmark time (avg) iter/s (min … max) p75 p99 p995 ------------------------------------------------------------------ ----------------------------- headers iter 9.6 µs/iter 104,134.1 (8.74 µs … 131.31 µs) 9.47 µs 12.61 µs 17.81 µs ``` **main** ``` cpu: 13th Gen Intel(R) Core(TM) i9-13900H runtime: deno 1.36.1 (x86_64-unknown-linux-gnu) benchmark time (avg) iter/s (min … max) p75 p99 p995 ------------------------------------------------------------------ ----------------------------- headers iter 12.87 µs/iter 77,675.9 (11.97 µs … 132.34 µs) 12.76 µs 16.49 µs 26.4 µs ``` ```js const headers = new Headers({ "Content-Type": "application/json", "X-Content-Type": "application/json", "Date": "Thu, 14 Aug 2023 17:45:10 GMT", "X-Deno": "Deno", "Powered-By": "Deno", "Content-Encoding": "gzip", "Set-Cookie": "__Secure-ID=123; Secure; Domain=example.com", "Content-Length": "150", "Vary": "Accept-Encoding, Accept, X-Requested-With", }); Deno.bench('headers iter', () => { [...headers] }) ```
This commit is contained in:
parent
049aebee34
commit
e77d55839d
1 changed files with 11 additions and 14 deletions
|
@ -26,7 +26,6 @@ const {
|
|||
ArrayPrototypeSort,
|
||||
ArrayPrototypeJoin,
|
||||
ArrayPrototypeSplice,
|
||||
ObjectEntries,
|
||||
ObjectHasOwn,
|
||||
RegExpPrototypeTest,
|
||||
Symbol,
|
||||
|
@ -238,8 +237,8 @@ class Headers {
|
|||
|
||||
// The order of steps are not similar to the ones suggested by the
|
||||
// spec but produce the same result.
|
||||
const headers = {};
|
||||
const cookies = [];
|
||||
const seenHeaders = {};
|
||||
const entries = [];
|
||||
for (let i = 0; i < list.length; ++i) {
|
||||
const entry = list[i];
|
||||
const name = byteLowerCase(entry[0]);
|
||||
|
@ -250,27 +249,25 @@ class Headers {
|
|||
// so must be given to the user as multiple headers.
|
||||
// The else block of the if statement is spec compliant again.
|
||||
if (name === "set-cookie") {
|
||||
ArrayPrototypePush(cookies, [name, value]);
|
||||
ArrayPrototypePush(entries, [name, value]);
|
||||
} else {
|
||||
// The following code has the same behaviour as getHeader()
|
||||
// at the end of loop. But it avoids looping through the entire
|
||||
// list to combine multiple values with same header name. It
|
||||
// instead gradually combines them as they are found.
|
||||
let header = headers[name];
|
||||
if (header && header.length > 0) {
|
||||
header += "\x2C\x20" + value;
|
||||
const seenHeaderIndex = seenHeaders[name];
|
||||
if (seenHeaderIndex !== undefined) {
|
||||
const entryValue = entries[seenHeaderIndex][1];
|
||||
entries[seenHeaderIndex][1] = entryValue.length > 0
|
||||
? entryValue + "\x2C\x20" + value
|
||||
: value;
|
||||
} else {
|
||||
header = value;
|
||||
seenHeaders[name] = entries.length; // store header index in entries array
|
||||
ArrayPrototypePush(entries, [name, value]);
|
||||
}
|
||||
headers[name] = header;
|
||||
}
|
||||
}
|
||||
|
||||
const entries = ObjectEntries(headers);
|
||||
for (let i = 0; i < cookies.length; ++i) {
|
||||
ArrayPrototypePush(entries, cookies[i]);
|
||||
}
|
||||
|
||||
ArrayPrototypeSort(
|
||||
entries,
|
||||
(a, b) => {
|
||||
|
|
Loading…
Reference in a new issue