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

url: avoid instanceof for WHATWG URL #11690

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion benchmark/url/url-searchparams-read.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { URLSearchParams } = require('url');
const bench = common.createBenchmark(main, {
method: ['get', 'getAll', 'has'],
param: ['one', 'two', 'three', 'nonexistent'],
n: [1e6]
n: [2e7]
});

const str = 'one=single&two=first&three=first&two=2nd&three=2nd&three=3rd';
Expand Down
2 changes: 1 addition & 1 deletion benchmark/url/whatwg-url-properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ const bench = common.createBenchmark(main, {
prop: ['href', 'origin', 'protocol',
'username', 'password', 'host', 'hostname', 'port',
'pathname', 'search', 'searchParams', 'hash'],
n: [1e4]
n: [3e5]
});

function setAndGet(n, url, prop, alternative) {
Expand Down
36 changes: 21 additions & 15 deletions lib/internal/url.js
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,10 @@ class URL {
constructor(input, base) {
// toUSVString is not needed.
input = `${input}`;
if (base !== undefined && !(base instanceof URL))
if (base !== undefined &&
(!base[searchParams] || !base[searchParams][searchParams])) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mscdex ... is there benefit to moving this into a separate isURL(u) function that can be exported by internal/url?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Performance-wise? No. There's actually a small but measurable performance hit when extracting all of the logic to a separate function, compared to having it inline. For example:

                                                                              improvement confidence      p.value
 url/url-searchparams-read.js n=20000000 param="nonexistent" method="get"       165.07 %        *** 1.189398e-66
 url/url-searchparams-read.js n=20000000 param="nonexistent" method="getAll"    139.46 %        *** 4.331942e-46
 url/url-searchparams-read.js n=20000000 param="nonexistent" method="has"       161.48 %        *** 2.741360e-52
 url/url-searchparams-read.js n=20000000 param="one" method="get"               222.70 %        *** 3.111318e-46
 url/url-searchparams-read.js n=20000000 param="one" method="getAll"            113.31 %        *** 1.122968e-53
 url/url-searchparams-read.js n=20000000 param="one" method="has"               232.04 %        *** 1.571222e-55
 url/url-searchparams-read.js n=20000000 param="three" method="get"             184.13 %        *** 2.078669e-48
 url/url-searchparams-read.js n=20000000 param="three" method="getAll"          100.34 %        *** 4.591714e-56
 url/url-searchparams-read.js n=20000000 param="three" method="has"             181.29 %        *** 7.340053e-43
 url/url-searchparams-read.js n=20000000 param="two" method="get"               209.77 %        *** 4.581349e-54
 url/url-searchparams-read.js n=20000000 param="two" method="getAll"            102.89 %        *** 2.001755e-36
 url/url-searchparams-read.js n=20000000 param="two" method="has"               203.09 %        *** 1.810527e-44

base = new URL(base);
}
parse(this, input, base);
}

Expand Down Expand Up @@ -885,7 +887,7 @@ class URLSearchParams {
}

[util.inspect.custom](recurseTimes, ctx) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}

Expand Down Expand Up @@ -947,7 +949,7 @@ function merge(out, start, mid, end, lBuffer, rBuffer) {

defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
append(name, value) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}
if (arguments.length < 2) {
Expand All @@ -961,7 +963,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
},

delete(name) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}
if (arguments.length < 1) {
Expand All @@ -982,7 +984,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
},

get(name) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}
if (arguments.length < 1) {
Expand All @@ -1000,7 +1002,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
},

getAll(name) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}
if (arguments.length < 1) {
Expand All @@ -1019,7 +1021,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
},

has(name) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}
if (arguments.length < 1) {
Expand All @@ -1037,7 +1039,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
},

set(name, value) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}
if (arguments.length < 2) {
Expand Down Expand Up @@ -1125,15 +1127,15 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
// Define entries here rather than [Symbol.iterator] as the function name
// must be set to `entries`.
entries() {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}

return createSearchParamsIterator(this, 'key+value');
},

forEach(callback, thisArg = undefined) {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}
if (typeof callback !== 'function') {
Expand All @@ -1155,15 +1157,15 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {

// https://heycam.github.io/webidl/#es-iterable
keys() {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}

return createSearchParamsIterator(this, 'key');
},

values() {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}

Expand All @@ -1173,7 +1175,7 @@ defineIDLClass(URLSearchParams.prototype, 'URLSearchParams', {
// https://heycam.github.io/webidl/#es-stringifier
// https://url.spec.whatwg.org/#urlsearchparams-stringification-behavior
toString() {
if (!this || !(this instanceof URLSearchParams)) {
if (!this || !this[searchParams] || this[searchParams][searchParams]) {
throw new TypeError('Value of `this` is not a URLSearchParams');
}

Expand Down Expand Up @@ -1275,8 +1277,10 @@ defineIDLClass(URLSearchParamsIteratorPrototype, 'URLSearchParamsIterator', {
});

function originFor(url, base) {
if (!(url instanceof URL))
if (url != undefined &&
(!url[searchParams] || !url[searchParams][searchParams])) {
url = new URL(url, base);
}
var origin;
const protocol = url.protocol;
switch (protocol) {
Expand Down Expand Up @@ -1393,8 +1397,10 @@ function getPathFromURLPosix(url) {
}

function getPathFromURL(path) {
if (!(path instanceof URL))
if (path == undefined || !path[searchParams] ||
!path[searchParams][searchParams]) {
return path;
}
if (path.protocol !== 'file:')
return new TypeError('Only `file:` URLs are supported');
return isWindows ? getPathFromURLWin32(path) : getPathFromURLPosix(path);
Expand Down