Skip to content

Commit 69e11d8

Browse files
committed
faster brand check
1 parent b6d53fe commit 69e11d8

File tree

8 files changed

+46
-21
lines changed

8 files changed

+46
-21
lines changed

benchmarks/fetch/webidl-is.mjs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { bench, run, barplot } from 'mitata'
2+
import { Headers, FormData } from '../../index.js'
3+
import { webidl } from '../../lib/web/fetch/webidl.js'
4+
5+
const headers = new Headers()
6+
const fd = new FormData()
7+
8+
barplot(() => {
9+
bench('webidl.is.FormData (ok)', () => {
10+
return webidl.is.FormData(fd)
11+
})
12+
13+
bench('webidl.is.FormData (bad)', () => {
14+
return !webidl.is.FormData(headers)
15+
})
16+
17+
bench('instanceof (ok)', () => {
18+
return fd instanceof FormData
19+
})
20+
21+
bench('instanceof (bad)', () => {
22+
return !(headers instanceof FormData)
23+
})
24+
})
25+
26+
await run()

lib/web/fetch/formdata.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,6 @@ function makeEntry (name, value, filename) {
256256
return { name, value }
257257
}
258258

259-
webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData.prototype)
259+
webidl.is.FormData = webidl.util.MakeTypeAssertion(FormData)
260260

261261
module.exports = { FormData, makeEntry, setFormDataState }

lib/web/fetch/request.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ Object.defineProperties(Request.prototype, {
986986
}
987987
})
988988

989-
webidl.is.Request = webidl.util.MakeTypeAssertion(Request.prototype)
989+
webidl.is.Request = webidl.util.MakeTypeAssertion(Request)
990990

991991
// https://fetch.spec.whatwg.org/#requestinfo
992992
webidl.converters.RequestInfo = function (V, prefix, argument) {

lib/web/fetch/response.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -619,7 +619,7 @@ webidl.converters.ResponseInit = webidl.dictionaryConverter([
619619
}
620620
])
621621

622-
webidl.is.Response = webidl.util.MakeTypeAssertion(Response.prototype)
622+
webidl.is.Response = webidl.util.MakeTypeAssertion(Response)
623623

624624
module.exports = {
625625
isNetworkError,

lib/web/fetch/webidl.js

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ const BIGINT = 6
1212
const NULL = 7
1313
const OBJECT = 8 // function and object
1414

15+
const FunctionPrototypeSymbolHasInstance = Function.call.bind(Function.prototype[Symbol.hasInstance])
16+
1517
/** @type {import('../../../types/webidl').Webidl} */
1618
const webidl = {
1719
converters: {},
@@ -45,15 +47,15 @@ webidl.errors.invalidArgument = function (context) {
4547

4648
// https://webidl.spec.whatwg.org/#implements
4749
webidl.brandCheck = function (V, I) {
48-
if (!I.prototype.isPrototypeOf(V)) { // eslint-disable-line no-prototype-builtins
50+
if (!FunctionPrototypeSymbolHasInstance(I, V)) {
4951
const err = new TypeError('Illegal invocation')
5052
err.code = 'ERR_INVALID_THIS' // node compat.
5153
throw err
5254
}
5355
}
5456

5557
webidl.brandCheckMultiple = function (List) {
56-
const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c.prototype))
58+
const prototypes = List.map((c) => webidl.util.MakeTypeAssertion(c))
5759

5860
return (V) => {
5961
if (prototypes.every(typeCheck => !typeCheck(V))) {
@@ -81,9 +83,8 @@ webidl.illegalConstructor = function () {
8183
})
8284
}
8385

84-
const isPrototypeOf = Object.prototype.isPrototypeOf
85-
webidl.util.MakeTypeAssertion = function (Prototype) {
86-
return (O) => isPrototypeOf.call(Prototype, O)
86+
webidl.util.MakeTypeAssertion = function (I) {
87+
return (O) => FunctionPrototypeSymbolHasInstance(I, O)
8788
}
8889

8990
// https://tc39.es/ecma262/#sec-ecmascript-data-types-and-values
@@ -462,13 +463,13 @@ webidl.nullableConverter = function (converter) {
462463
}
463464
}
464465

465-
webidl.is.ReadableStream = webidl.util.MakeTypeAssertion(ReadableStream.prototype)
466-
webidl.is.Blob = webidl.util.MakeTypeAssertion(Blob.prototype)
467-
webidl.is.URLSearchParams = webidl.util.MakeTypeAssertion(URLSearchParams.prototype)
468-
webidl.is.File = webidl.util.MakeTypeAssertion((globalThis.File ?? require('node:buffer').File).prototype)
469-
webidl.is.URL = webidl.util.MakeTypeAssertion(URL.prototype)
470-
webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal.prototype)
471-
webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort.prototype)
466+
webidl.is.ReadableStream = webidl.util.MakeTypeAssertion(ReadableStream)
467+
webidl.is.Blob = webidl.util.MakeTypeAssertion(Blob)
468+
webidl.is.URLSearchParams = webidl.util.MakeTypeAssertion(URLSearchParams)
469+
webidl.is.File = webidl.util.MakeTypeAssertion(globalThis.File ?? require('node:buffer').File)
470+
webidl.is.URL = webidl.util.MakeTypeAssertion(URL)
471+
webidl.is.AbortSignal = webidl.util.MakeTypeAssertion(AbortSignal)
472+
webidl.is.MessagePort = webidl.util.MakeTypeAssertion(MessagePort)
472473

473474
// https://webidl.spec.whatwg.org/#es-DOMString
474475
webidl.converters.DOMString = function (V, prefix, argument, opts) {

lib/web/websocket/stream/websocketerror.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,6 @@ Object.defineProperties(WebSocketError.prototype, {
7878
}
7979
})
8080

81-
webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError.prototype)
81+
webidl.is.WebSocketError = webidl.util.MakeTypeAssertion(WebSocketError)
8282

8383
module.exports = { WebSocketError, createUnvalidatedWebSocketError }

test/webidl/helpers.js

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ test('webidl.interfaceConverter', (t) => {
88
class A {}
99
class B {}
1010

11-
const converter = webidl.interfaceConverter(
12-
webidl.util.MakeTypeAssertion(A.prototype)
13-
)
11+
const converter = webidl.interfaceConverter(webidl.util.MakeTypeAssertion(A))
1412

1513
assert.throws(() => {
1614
converter(new B(), 'converter', 'converter')

types/webidl.d.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ interface WebidlUtil {
8484
*/
8585
Stringify (V: any): string
8686

87-
MakeTypeAssertion <T extends { prototype: T }>(Prototype: T['prototype']): (arg: any) => arg is T
87+
MakeTypeAssertion <I extends abstract new (...args: any[]) => any>(I: I): (arg: any) => arg is InstanceType<I>
8888
}
8989

9090
interface WebidlConverters {
@@ -176,7 +176,7 @@ interface WebidlConverters {
176176
[Key: string]: (...args: any[]) => unknown
177177
}
178178

179-
type IsAssertion<T> = (arg: any) => arg is T
179+
type IsAssertion<T extends abstract new (...args: any[]) => any> = (arg: any) => arg is InstanceType<T>
180180

181181
interface WebidlIs {
182182
Request: IsAssertion<undici.Request>

0 commit comments

Comments
 (0)