Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

perf(request): optimize if headers are given #2454

Merged
merged 14 commits into from
Nov 26, 2023
18 changes: 18 additions & 0 deletions lib/fetch/headers.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,19 @@ function appendHeader (headers, name, value) {
// privileged no-CORS request headers from headers
}

/**
* @param {HeadersList} A copy destination
* @param {HeadersList} B copy source
*/
function headersListCopy (A, B) {
if (B[kHeadersMap].size !== 0) {
for (const entry of B[kHeadersMap]) {
A[kHeadersMap].set(entry[0], entry[1])
}
A.cookies = B.cookies === null ? null : [...B.cookies]
}
}

class HeadersList {
/** @type {[string, string][]|null} */
cookies = null
Expand Down Expand Up @@ -224,6 +237,10 @@ class HeadersList {
}
}

get mapSize () {
return this[kHeadersMap].size
}

get entries () {
const headers = {}

Expand Down Expand Up @@ -581,6 +598,7 @@ webidl.converters.HeadersInit = function (V) {

module.exports = {
fill,
headersListCopy,
Headers,
HeadersList
}
22 changes: 10 additions & 12 deletions lib/fetch/request.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
'use strict'

const { extractBody, mixinBody, cloneBody } = require('./body')
const { Headers, fill: fillHeaders, HeadersList } = require('./headers')
const { Headers, fill: fillHeaders, HeadersList, headersListCopy } = require('./headers')
const { FinalizationRegistry } = require('../compat/dispatcher-weakref')()
const util = require('../core/util')
const {
Expand Down Expand Up @@ -415,25 +415,23 @@ class Request {
}

// 32. If init is not empty, then:
if (Object.keys(init).length !== 0) {
// Note: Avoid call `Object.keys` if init["headers"] is not undefined.
if (init.headers !== undefined || Object.keys(init).length !== 0) {
// 1. Let headers be a copy of this’s headers and its associated header
// list.
let headers = new Headers(this[kHeaders])

// 2. If init["headers"] exists, then set headers to init["headers"].
if (init.headers !== undefined) {
headers = init.headers
}
// Note: Avoid call `HeadersList` if init["headers"] is not undefined
const headers = init.headers !== undefined ? init.headers : new HeadersList(request.headersList)

// 3. Empty this’s headers’s header list.
this[kHeaders][kHeadersList].clear()
// Note: Avoid call `HeadersList#clear` if already empty
if (request.headersList.mapSize !== 0) request.headersList.clear()

// 4. If headers is a Headers object, then for each header in its header
// list, append header’s name/header’s value to this’s headers.
if (headers.constructor.name === 'Headers') {
for (const [key, val] of headers) {
this[kHeaders].append(key, val)
}
// Note: If init["headers"] is undefined, then it is `HeadersList`.
if (init.headers === undefined) {
headersListCopy(request.headersList, headers)
} else {
// 5. Otherwise, fill this’s headers with headers.
fillHeaders(this[kHeaders], headers)
Expand Down