1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-25 15:29:32 -05:00

perf(ext/request): optimize validate and normalize HTTP method (#20143)

This PR optimizes `Request` constructor init method step. It doubles the
speed for known lowercased methods. I also added `PATCH` to known
methods

**this patch**

```
benchmark                   time (avg)        iter/s             (min … max)       p75       p99      p995
---------------------------------------------------------------------------- -----------------------------
method: GET                  1.49 µs/iter     669,336.9     (1.35 µs … 2.02 µs)   1.54 µs   2.02 µs   2.02 µs
method: PATCH                1.85 µs/iter     540,921.5     (1.65 µs … 2.02 µs)   1.91 µs   2.02 µs   2.02 µs
method: get                  1.49 µs/iter     669,067.9     (1.28 µs … 1.69 µs)   1.55 µs   1.69 µs   1.69 µ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
---------------------------------------------------------------------------- -----------------------------
method: GET                   1.5 µs/iter     665,232.3      (1.3 µs … 2.02 µs)   1.54 µs   2.02 µs   2.02 µs
method: PATCH                2.47 µs/iter     404,052.7     (2.06 µs … 4.05 µs)   2.51 µs   4.05 µs   4.05 µs
method: get                     3 µs/iter     333,277.2     (2.72 µs … 4.04 µs)   3.05 µs   4.04 µs   4.04 µs
```

```js
Deno.bench("method: GET", () => {
  const r = new Request("https://deno.land", {
    method: "GET",
  });
});

Deno.bench("method: PATCH", () => {
  const r = new Request("https://deno.land", {
    method: "PATCH",
    body: '{"foo": "bar"}',
  });
});

Deno.bench("method: get", () => {
  const r = new Request("https://deno.land", {
    method: "get",
  });
});
```
This commit is contained in:
Marcos Casagrande 2023-08-12 20:29:00 +02:00 committed by GitHub
parent b34bd640a6
commit 050ca39409
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -202,31 +202,29 @@ function cloneInnerRequest(request, skipBody = false) {
}; };
} }
/** // method => normalized method
* @param {string} m const KNOWN_METHODS = {
* @returns {boolean} "DELETE": "DELETE",
*/ "delete": "DELETE",
function isKnownMethod(m) { "GET": "GET",
return ( "get": "GET",
m === "DELETE" || "HEAD": "HEAD",
m === "GET" || "head": "HEAD",
m === "HEAD" || "OPTIONS": "OPTIONS",
m === "OPTIONS" || "options": "OPTIONS",
m === "POST" || "PATCH": "PATCH",
m === "PUT" "patch": "PATCH",
); "POST": "POST",
} "post": "POST",
"PUT": "PUT",
"put": "PUT",
};
/** /**
* @param {string} m * @param {string} m
* @returns {string} * @returns {string}
*/ */
function validateAndNormalizeMethod(m) { function validateAndNormalizeMethod(m) {
// Fast path for well-known methods
if (isKnownMethod(m)) {
return m;
}
// Regular path
if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, m) === null) { if (RegExpPrototypeExec(HTTP_TOKEN_CODE_POINT_RE, m) === null) {
throw new TypeError("Method is not valid."); throw new TypeError("Method is not valid.");
} }
@ -325,9 +323,10 @@ class Request {
// 25. // 25.
if (init.method !== undefined) { if (init.method !== undefined) {
let method = init.method; const method = init.method;
method = validateAndNormalizeMethod(method); // fast path: check for known methods
request.method = method; request.method = KNOWN_METHODS[method] ??
validateAndNormalizeMethod(method);
} }
// 26. // 26.