0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

perf: lazy header instantiation for HTTP requests (#10150)

This commit introduces a performance optimization for the native HTTP
server. From my testing it is about 2-6% faster than `main`. Request
headers in the HTTP servers are now lazilly instatated when they are
accessed, rather than being preemptively wrapped in the `Headers` class.
This commit is contained in:
Luca Casonato 2021-04-13 02:46:33 +02:00 committed by GitHub
parent 9f26e639dd
commit dabce813e0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 28 additions and 6 deletions

View file

@ -686,6 +686,7 @@
// fastBody and dontValidateUrl allow users to opt out of certain behaviors
const fastBody = Symbol("Body#fast");
const dontValidateUrl = Symbol("dontValidateUrl");
const lazyHeaders = Symbol("lazyHeaders");
class Body {
#contentType = "";
@ -960,7 +961,7 @@
#method = "GET";
/** @type {string} */
#url = "";
/** @type {Headers} */
/** @type {Headers | string[][]} */
#headers;
/** @type {"include" | "omit" | "same-origin" | undefined} */
#credentials = "omit";
@ -999,16 +1000,32 @@
}
let headers;
let contentType = "";
// prefer headers from init
if (init.headers) {
headers = new Headers(init.headers);
if (init[lazyHeaders] && Array.isArray(init.headers)) {
// Trust the headers are valid, and only put them into the `Headers`
// strucutre when the user accesses the property. We also assume that
// all passed headers are lower-case (as is the case when they come
// from hyper in Rust), and that headers are of type
// `[string, string][]`.
headers = init.headers;
for (const tuple of headers) {
if (tuple[0] === "content-type") {
contentType = tuple[1];
}
}
} else {
headers = new Headers(init.headers);
contentType = headers.get("content-type") || "";
}
} else if (input instanceof Request) {
headers = input.headers;
contentType = headers.get("content-type") || "";
} else {
headers = new Headers();
}
const contentType = headers.get("content-type") || "";
super(b, { contentType });
this.#headers = headers;
@ -1016,9 +1033,9 @@
if (input.bodyUsed) {
throw TypeError(BodyUsedError);
}
// headers are already set above. no reason to do it again
this.#method = input.method;
this.#url = input.url;
this.#headers = new Headers(input.headers);
this.#credentials = input.credentials;
} else {
// Constructing a URL just for validation is known to be expensive.
@ -1085,6 +1102,9 @@
}
get headers() {
if (!(this.#headers instanceof Headers)) {
this.#headers = new Headers(this.#headers);
}
return this.#headers;
}
@ -1515,5 +1535,6 @@
createHttpClient,
fastBody,
dontValidateUrl,
lazyHeaders,
};
})(this);

View file

@ -2,7 +2,7 @@
"use strict";
((window) => {
const { Request, dontValidateUrl, fastBody, Response } =
const { Request, dontValidateUrl, lazyHeaders, fastBody, Response } =
window.__bootstrap.fetch;
const { Headers } = window.__bootstrap.headers;
const errors = window.__bootstrap.errors.errors;
@ -61,8 +61,9 @@
const request = new Request(url, {
body,
method,
headers: new Headers(headersList),
headers: headersList,
[dontValidateUrl]: true,
[lazyHeaders]: true,
});
const respondWith = createRespondWith(responseSenderRid, this.#rid);