Skip to content

Commit

Permalink
perf: use class make faster
Browse files Browse the repository at this point in the history
  • Loading branch information
tsctx committed Feb 12, 2024
1 parent 0962d5a commit 19a7d8d
Showing 1 changed file with 59 additions and 51 deletions.
110 changes: 59 additions & 51 deletions lib/fetch/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -745,55 +745,72 @@ const esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbo
* @param {string | number} [keyIndex]
* @param {string | number} [valueIndex]
*/
function createIterator (name, kInternalIterator, keyIndex = 0, valueIndex = 1) {
const kInternalObject = Symbol('internal Object')

// The [[Prototype]] internal slot of an iterator prototype object must be %IteratorPrototype%.
const iteratorObject = Object.create(esIteratorPrototype)
function createFastIterator (name, kInternalIterator, keyIndex = 0, valueIndex = 1) {
class FastIterableIterator {
/** @type {any} */
#target
/** @type {'key' | 'value' | 'key+value'} */
#kind
/** @type {number} */
#index

/**
* @see https://webidl.spec.whatwg.org/#dfn-default-iterator-object
* @param {unknown} target
* @param {'key' | 'value' | 'key+value'} kind
*/
constructor (target, kind) {
this.#target = target
this.#kind = kind
this.#index = 0
}

Object.defineProperty(iteratorObject, 'next', {
value: function next () {
next () {
// 1. Let interface be the interface for which the iterator prototype object exists.

// 2. Let thisValue be the this value.

// 3. Let object be ? ToObject(thisValue).

// 4. If object is a platform object, then perform a security
// check, passing:

// 5. If object is not a default iterator object for interface,
// then throw a TypeError.
if (typeof this !== 'object' || this === null || !(kInternalObject in this)) {
// Object.getPrototypeOf(this) !== FastIterator.prototype
if (typeof this !== 'object' || this === null || !(#target in this)) {
throw new TypeError(
`'next' called on an object that does not implement interface ${name} Iterator.`
)
}
const object = this[kInternalObject]

// 6. Let index be object’s index.
// 7. Let kind be object’s kind.
// 8. Let values be object’s target's value pairs to iterate over.
const { index, kind, target } = object
const values = target[kInternalIterator]
const index = this.#index
const values = this.#target[kInternalIterator]

// 9. Let len be the length of values.
const len = values.length

// 10. If index is greater than or equal to len, then return
// CreateIterResultObject(undefined, true).
if (index >= len) {
return { value: undefined, done: true }
return {
value: undefined,
done: true
}
}

// 11. Let pair be the entry in values at index index.
const { [keyIndex]: key, [valueIndex]: value } = values[index]

// 12. Set object’s index to index + 1.
object.index = index + 1
this.#index = index + 1

// 13. Return the iterator result for pair and kind.

// https://webidl.spec.whatwg.org/#iterator-result

// 1. Let result be a value determined by the value of kind:
let result
switch (kind) {
switch (this.#kind) {
case 'key':
// 1. Let idlKey be pair’s key.
// 2. Let key be the result of converting idlKey to an
Expand Down Expand Up @@ -822,45 +839,37 @@ function createIterator (name, kInternalIterator, keyIndex = 0, valueIndex = 1)
result = [key, value]
break
}

// 2. Return CreateIterResultObject(result, false).
return {
value: result,
done: false
}
},
writable: true,
enumerable: true,
configurable: true
})
}
}

// https://webidl.spec.whatwg.org/#dfn-iterator-prototype-object
// @ts-ignore
delete FastIterableIterator.prototype.constructor

Object.setPrototypeOf(FastIterableIterator.prototype, esIteratorPrototype)

// The class string of an iterator prototype object for a given interface is the
// result of concatenating the identifier of the interface and the string " Iterator".
Object.defineProperty(iteratorObject, Symbol.toStringTag, {
value: `${name} Iterator`,
writable: false,
enumerable: false,
configurable: true
Object.defineProperties(FastIterableIterator.prototype, {
[Symbol.toStringTag]: {
writable: false,
enumerable: false,
configurable: true,
value: `${name} Iterator`
},
next: { writable: true, enumerable: true, configurable: true }
})

/**
* @param {unknown} target
* @param {'key'|'value'|'key+value'} kind
* @param {'key' | 'value' | 'key+value'} kind
*/
return function (target, kind) {
// esIteratorPrototype needs to be the prototype of iteratorObject
// which is the prototype of an empty object. Yes, it's confusing.
const iterator = Object.create(iteratorObject)
Object.defineProperty(iterator, kInternalObject, {
value: {
target,
kind,
index: 0
},
writable: false,
enumerable: false,
configurable: true
})
return iterator
return new FastIterableIterator(target, kind)
}
}

Expand All @@ -873,7 +882,7 @@ function createIterator (name, kInternalIterator, keyIndex = 0, valueIndex = 1)
* @param {string | number} [valueIndex]
*/
function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueIndex = 1) {
const makeIterator = createIterator(name, kInternalIterator, keyIndex, valueIndex)
const createIterator = createFastIterator(name, kInternalIterator, keyIndex, valueIndex)

const properties = {
keys: {
Expand All @@ -882,7 +891,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
configurable: true,
value: function keys () {
webidl.brandCheck(this, object)
return makeIterator(this, 'key')
return createIterator(this, 'key')
}
},
values: {
Expand All @@ -891,7 +900,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
configurable: true,
value: function values () {
webidl.brandCheck(this, object)
return makeIterator(this, 'value')
return createIterator(this, 'value')
}
},
entries: {
Expand All @@ -900,7 +909,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
configurable: true,
value: function entries () {
webidl.brandCheck(this, object)
return makeIterator(this, 'key+value')
return createIterator(this, 'key+value')
}
},
forEach: {
Expand All @@ -915,7 +924,7 @@ function iteratorMixin (name, object, kInternalIterator, keyIndex = 0, valueInde
`Failed to execute 'forEach' on '${name}': parameter 1 is not of type 'Function'.`
)
}
for (const { 0: key, 1: value } of makeIterator(this, 'key+value')) {
for (const { 0: key, 1: value } of createIterator(this, 'key+value')) {
callbackfn.call(thisArg, value, key, this)
}
}
Expand Down Expand Up @@ -1448,7 +1457,6 @@ module.exports = {
sameOrigin,
normalizeMethod,
serializeJavascriptValueToJSONString,
createIterator,
iteratorMixin,
isValidHeaderName,
isValidHeaderValue,
Expand Down

0 comments on commit 19a7d8d

Please sign in to comment.