Repository: denoland/deno
Pull request: perf(http): cache webidl.converters lookups in ext/fetch/23_response.js

Code:

```js
Deno.bench("response", () => {
  const responses = [];
  for (var i = 0; i < 1024 * 1024; i++) {
    responses.push(new Response(i.toString()));
  }
  return responses;
});
```

Before:

```
response           572.2 ms           1.7 (443.7 ms … 752.5 ms) 679.6 ms 752.5 ms 752.5 ms
```

After:

```
response           543.3 ms           1.8 (369.5 ms … 721.8 ms) 606.3 ms 721.8 ms 721.8 ms
```

Changed files:
filename: ext/fetch/23_response.js
patch: @@ -61,6 +61,15 @@ const _mimeType = Symbol("mime type");
 const _body = Symbol("body");
 const _brand = webidl.brand;
 
+// it's slightly faster to cache these
+const webidlConvertersBodyInitDomString =
+  webidl.converters["BodyInit_DOMString?"];
+const webidlConvertersUSVString = webidl.converters["USVString"];
+const webidlConvertersUnsignedShort = webidl.converters["unsigned short"];
+const webidlConvertersAny = webidl.converters["any"];
+const webidlConvertersByteString = webidl.converters["ByteString"];
+const webidlConvertersHeadersInit = webidl.converters["HeadersInit"];
+
 /**
  * @typedef InnerResponse
  * @property {"basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect"} type
@@ -259,8 +268,8 @@ class Response {
    */
   static redirect(url, status = 302) {
     const prefix = "Failed to execute 'Response.redirect'";
-    url = webidl.converters["USVString"](url, prefix, "Argument 1");
-    status = webidl.converters["unsigned short"](status, prefix, "Argument 2");
+    url = webidlConvertersUSVString(url, prefix, "Argument 1");
+    status = webidlConvertersUnsignedShort(status, prefix, "Argument 2");
 
     const baseURL = getLocationHref();
     const parsedURL = new URL(url, baseURL);
@@ -286,8 +295,8 @@ class Response {
    */
   static json(data = undefined, init = { __proto__: null }) {
     const prefix = "Failed to execute 'Response.json'";
-    data = webidl.converters.any(data);
-    init = webidl.converters["ResponseInit_fast"](init, prefix, "Argument 2");
+    data = webidlConvertersAny(data);
+    init = webidlConvertersResponseInitFast(init, prefix, "Argument 2");
 
     const str = serializeJSValueToJSONString(data);
     const res = extractBody(str);
@@ -313,8 +322,8 @@ class Response {
     }
 
     const prefix = "Failed to construct 'Response'";
-    body = webidl.converters["BodyInit_DOMString?"](body, prefix, "Argument 1");
-    init = webidl.converters["ResponseInit_fast"](init, prefix, "Argument 2");
+    body = webidlConvertersBodyInitDomString(body, prefix, "Argument 1");
+    init = webidlConvertersResponseInitFast(init, prefix, "Argument 2");
 
     this[_response] = newInnerResponse();
     this[_headers] = headersFromHeaderList(
@@ -443,47 +452,49 @@ webidl.converters["Response"] = webidl.createInterfaceConverter(
   "Response",
   ResponsePrototype,
 );
-webidl.converters["ResponseInit"] = webidl.createDictionaryConverter(
-  "ResponseInit",
-  [{
-    key: "status",
-    defaultValue: 200,
-    converter: webidl.converters["unsigned short"],
-  }, {
-    key: "statusText",
-    defaultValue: "",
-    converter: webidl.converters["ByteString"],
-  }, {
-    key: "headers",
-    converter: webidl.converters["HeadersInit"],
-  }],
-);
-webidl.converters["ResponseInit_fast"] = function (
-  init,
-  prefix,
-  context,
-  opts,
-) {
-  if (init === undefined || init === null) {
-    return { status: 200, statusText: "", headers: undefined };
-  }
-  // Fast path, if not a proxy
-  if (typeof init === "object" && !core.isProxy(init)) {
-    // Not a proxy fast path
-    const status = init.status !== undefined
-      ? webidl.converters["unsigned short"](init.status)
-      : 200;
-    const statusText = init.statusText !== undefined
-      ? webidl.converters["ByteString"](init.statusText)
-      : "";
-    const headers = init.headers !== undefined
-      ? webidl.converters["HeadersInit"](init.headers)
-      : undefined;
-    return { status, statusText, headers };
-  }
-  // Slow default path
-  return webidl.converters["ResponseInit"](init, prefix, context, opts);
-};
+const webidlConvertersResponseInit = webidl.converters["ResponseInit"] = webidl
+  .createDictionaryConverter(
+    "ResponseInit",
+    [{
+      key: "status",
+      defaultValue: 200,
+      converter: webidlConvertersUnsignedShort,
+    }, {
+      key: "statusText",
+      defaultValue: "",
+      converter: webidlConvertersByteString,
+    }, {
+      key: "headers",
+      converter: webidlConvertersHeadersInit,
+    }],
+  );
+const webidlConvertersResponseInitFast = webidl
+  .converters["ResponseInit_fast"] = function (
+    init,
+    prefix,
+    context,
+    opts,
+  ) {
+    if (init === undefined || init === null) {
+      return { status: 200, statusText: "", headers: undefined };
+    }
+    // Fast path, if not a proxy
+    if (typeof init === "object" && !core.isProxy(init)) {
+      // Not a proxy fast path
+      const status = init.status !== undefined
+        ? webidlConvertersUnsignedShort(init.status)
+        : 200;
+      const statusText = init.statusText !== undefined
+        ? webidlConvertersByteString(init.statusText)
+        : "";
+      const headers = init.headers !== undefined
+        ? webidlConvertersHeadersInit(init.headers)
+        : undefined;
+      return { status, statusText, headers };
+    }
+    // Slow default path
+    return webidlConvertersResponseInit(init, prefix, context, opts);
+  };
 
 /**
  * @param {Response} response