Skip to content

Commit b40f0c3

Browse files
anonrigMesteeryVoltrexKeyva
authored
lib: add navigator.hardwareConcurrency
Co-authored-by: Mestery <mestery@protonmail.com> Co-authored-by: Voltrex <mohammadkeyvanzade94@gmail.com> PR-URL: #47769 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
1 parent 74c2d9c commit b40f0c3

File tree

8 files changed

+120
-1
lines changed

8 files changed

+120
-1
lines changed

.eslintrc.js

+1
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ module.exports = {
328328
DecompressionStream: 'readable',
329329
fetch: 'readable',
330330
FormData: 'readable',
331+
navigator: 'readable',
331332
ReadableStream: 'readable',
332333
ReadableStreamDefaultReader: 'readable',
333334
ReadableStreamBYOBReader: 'readable',

doc/api/globals.md

+37
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,41 @@ The `MessagePort` class. See [`MessagePort`][] for more details.
583583

584584
This variable may appear to be global but is not. See [`module`][].
585585

586+
## `Navigator`
587+
588+
<!-- YAML
589+
added: REPLACEME
590+
-->
591+
592+
> Stability: 1 - Experimental
593+
594+
An implementation of the [Navigator API][].
595+
596+
## `navigator`
597+
598+
<!-- YAML
599+
added: REPLACEME
600+
-->
601+
602+
> Stability: 1 - Experimental
603+
604+
An implementation of [`window.navigator`][].
605+
606+
### `navigator.hardwareConcurrency`
607+
608+
<!-- YAML
609+
added: REPLACEME
610+
-->
611+
612+
* {number}
613+
614+
The `navigator.hardwareConcurrency` read-only property returns the number of
615+
logical processors available to the current Node.js instance.
616+
617+
```js
618+
console.log(`This process is running on ${navigator.hardwareConcurrency}`);
619+
```
620+
586621
## `PerformanceEntry`
587622

588623
<!-- YAML
@@ -998,6 +1033,7 @@ A browser-compatible implementation of [`WritableStreamDefaultWriter`][].
9981033

9991034
[CommonJS module]: modules.md
10001035
[ECMAScript module]: esm.md
1036+
[Navigator API]: https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
10011037
[Web Crypto API]: webcrypto.md
10021038
[`--no-experimental-fetch`]: cli.md#--no-experimental-fetch
10031039
[`--no-experimental-global-customevent`]: cli.md#--no-experimental-global-customevent
@@ -1057,6 +1093,7 @@ A browser-compatible implementation of [`WritableStreamDefaultWriter`][].
10571093
[`setInterval`]: timers.md#setintervalcallback-delay-args
10581094
[`setTimeout`]: timers.md#settimeoutcallback-delay-args
10591095
[`structuredClone`]: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
1096+
[`window.navigator`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator
10601097
[buffer section]: buffer.md
10611098
[built-in objects]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
10621099
[module system documentation]: modules.md

lib/.eslintrc.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ rules:
7575
message: Use `const { MessageEvent } = require('internal/worker/io');` instead of the global.
7676
- name: MessagePort
7777
message: Use `const { MessagePort } = require('internal/worker/io');` instead of the global.
78+
- name: Navigator
79+
message: Use `const { Navigator } = require('internal/navigator');` instead of the global.
80+
- name: navigator
81+
message: Use `const { navigator } = require('internal/navigator');` instead of the global.
7882
- name: PerformanceEntry
7983
message: Use `const { PerformanceEntry } = require('perf_hooks');` instead of the global.
8084
- name: PerformanceMark

lib/internal/bootstrap/web/exposed-window-or-worker.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
/**
44
* This file exposes web interfaces that is defined with the WebIDL
5-
* Exposed=(Window,Worker) extended attribute or exposed in
5+
* Exposed=Window + Exposed=(Window,Worker) extended attribute or exposed in
66
* WindowOrWorkerGlobalScope mixin.
77
* See more details at https://webidl.spec.whatwg.org/#Exposed and
88
* https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope.
@@ -55,6 +55,10 @@ exposeLazyInterfaces(globalThis, 'perf_hooks', [
5555

5656
defineReplaceableLazyAttribute(globalThis, 'perf_hooks', ['performance']);
5757

58+
// https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
59+
exposeLazyInterfaces(globalThis, 'internal/navigator', ['Navigator']);
60+
defineReplaceableLazyAttribute(globalThis, 'internal/navigator', ['navigator'], false);
61+
5862
// https://w3c.github.io/FileAPI/#creating-revoking
5963
const { installObjectURLMethods } = require('internal/url');
6064
installObjectURLMethods();

lib/internal/navigator.js

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
'use strict';
2+
3+
const {
4+
ObjectDefineProperties,
5+
Symbol,
6+
} = primordials;
7+
8+
const {
9+
ERR_ILLEGAL_CONSTRUCTOR,
10+
} = require('internal/errors').codes;
11+
12+
const {
13+
kEnumerableProperty,
14+
} = require('internal/util');
15+
16+
const {
17+
getAvailableParallelism,
18+
} = internalBinding('os');
19+
20+
const kInitialize = Symbol('kInitialize');
21+
22+
class Navigator {
23+
// Private properties are used to avoid brand validations.
24+
#availableParallelism;
25+
26+
constructor() {
27+
if (arguments[0] === kInitialize) {
28+
return;
29+
}
30+
throw ERR_ILLEGAL_CONSTRUCTOR();
31+
}
32+
33+
/**
34+
* @return {number}
35+
*/
36+
get hardwareConcurrency() {
37+
this.#availableParallelism ??= getAvailableParallelism();
38+
return this.#availableParallelism;
39+
}
40+
}
41+
42+
ObjectDefineProperties(Navigator.prototype, {
43+
hardwareConcurrency: kEnumerableProperty,
44+
});
45+
46+
module.exports = {
47+
navigator: new Navigator(kInitialize),
48+
Navigator,
49+
};

test/common/index.js

+8
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,14 @@ if (global.gc) {
309309
knownGlobals.push(global.gc);
310310
}
311311

312+
if (global.navigator) {
313+
knownGlobals.push(global.navigator);
314+
}
315+
316+
if (global.Navigator) {
317+
knownGlobals.push(global.Navigator);
318+
}
319+
312320
if (global.Performance) {
313321
knownGlobals.push(global.Performance);
314322
}

test/parallel/test-global.js

+1
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ builtinModules.forEach((moduleName) => {
5858
'structuredClone',
5959
'fetch',
6060
'crypto',
61+
'navigator',
6162
];
6263
assert.deepStrictEqual(new Set(Object.keys(global)), new Set(expected));
6364
}

test/parallel/test-navigator.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
'use strict';
2+
3+
require('../common');
4+
const assert = require('assert');
5+
6+
const is = {
7+
number: (value, key) => {
8+
assert(!Number.isNaN(value), `${key} should not be NaN`);
9+
assert.strictEqual(typeof value, 'number');
10+
},
11+
};
12+
13+
is.number(+navigator.hardwareConcurrency, 'hardwareConcurrency');
14+
is.number(navigator.hardwareConcurrency, 'hardwareConcurrency');
15+
assert.ok(navigator.hardwareConcurrency > 0);

0 commit comments

Comments
 (0)