Skip to content

Commit

Permalink
lib: add navigator.hardwareConcurrency
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
3 people authored Jul 4, 2023
1 parent 74c2d9c commit b40f0c3
Show file tree
Hide file tree
Showing 8 changed files with 120 additions and 1 deletion.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,7 @@ module.exports = {
DecompressionStream: 'readable',
fetch: 'readable',
FormData: 'readable',
navigator: 'readable',
ReadableStream: 'readable',
ReadableStreamDefaultReader: 'readable',
ReadableStreamBYOBReader: 'readable',
Expand Down
37 changes: 37 additions & 0 deletions doc/api/globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -583,6 +583,41 @@ The `MessagePort` class. See [`MessagePort`][] for more details.

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

## `Navigator`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental
An implementation of the [Navigator API][].

## `navigator`

<!-- YAML
added: REPLACEME
-->

> Stability: 1 - Experimental
An implementation of [`window.navigator`][].

### `navigator.hardwareConcurrency`

<!-- YAML
added: REPLACEME
-->

* {number}

The `navigator.hardwareConcurrency` read-only property returns the number of
logical processors available to the current Node.js instance.

```js
console.log(`This process is running on ${navigator.hardwareConcurrency}`);
```

## `PerformanceEntry`

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

[CommonJS module]: modules.md
[ECMAScript module]: esm.md
[Navigator API]: https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
[Web Crypto API]: webcrypto.md
[`--no-experimental-fetch`]: cli.md#--no-experimental-fetch
[`--no-experimental-global-customevent`]: cli.md#--no-experimental-global-customevent
Expand Down Expand Up @@ -1057,6 +1093,7 @@ A browser-compatible implementation of [`WritableStreamDefaultWriter`][].
[`setInterval`]: timers.md#setintervalcallback-delay-args
[`setTimeout`]: timers.md#settimeoutcallback-delay-args
[`structuredClone`]: https://developer.mozilla.org/en-US/docs/Web/API/structuredClone
[`window.navigator`]: https://developer.mozilla.org/en-US/docs/Web/API/Window/navigator
[buffer section]: buffer.md
[built-in objects]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects
[module system documentation]: modules.md
Expand Down
4 changes: 4 additions & 0 deletions lib/.eslintrc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ rules:
message: Use `const { MessageEvent } = require('internal/worker/io');` instead of the global.
- name: MessagePort
message: Use `const { MessagePort } = require('internal/worker/io');` instead of the global.
- name: Navigator
message: Use `const { Navigator } = require('internal/navigator');` instead of the global.
- name: navigator
message: Use `const { navigator } = require('internal/navigator');` instead of the global.
- name: PerformanceEntry
message: Use `const { PerformanceEntry } = require('perf_hooks');` instead of the global.
- name: PerformanceMark
Expand Down
6 changes: 5 additions & 1 deletion lib/internal/bootstrap/web/exposed-window-or-worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

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

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

// https://html.spec.whatwg.org/multipage/system-state.html#the-navigator-object
exposeLazyInterfaces(globalThis, 'internal/navigator', ['Navigator']);
defineReplaceableLazyAttribute(globalThis, 'internal/navigator', ['navigator'], false);

// https://w3c.github.io/FileAPI/#creating-revoking
const { installObjectURLMethods } = require('internal/url');
installObjectURLMethods();
49 changes: 49 additions & 0 deletions lib/internal/navigator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
'use strict';

const {
ObjectDefineProperties,
Symbol,
} = primordials;

const {
ERR_ILLEGAL_CONSTRUCTOR,
} = require('internal/errors').codes;

const {
kEnumerableProperty,
} = require('internal/util');

const {
getAvailableParallelism,
} = internalBinding('os');

const kInitialize = Symbol('kInitialize');

class Navigator {
// Private properties are used to avoid brand validations.
#availableParallelism;

constructor() {
if (arguments[0] === kInitialize) {
return;
}
throw ERR_ILLEGAL_CONSTRUCTOR();
}

/**
* @return {number}
*/
get hardwareConcurrency() {
this.#availableParallelism ??= getAvailableParallelism();
return this.#availableParallelism;
}
}

ObjectDefineProperties(Navigator.prototype, {
hardwareConcurrency: kEnumerableProperty,
});

module.exports = {
navigator: new Navigator(kInitialize),
Navigator,
};
8 changes: 8 additions & 0 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,14 @@ if (global.gc) {
knownGlobals.push(global.gc);
}

if (global.navigator) {
knownGlobals.push(global.navigator);
}

if (global.Navigator) {
knownGlobals.push(global.Navigator);
}

if (global.Performance) {
knownGlobals.push(global.Performance);
}
Expand Down
1 change: 1 addition & 0 deletions test/parallel/test-global.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ builtinModules.forEach((moduleName) => {
'structuredClone',
'fetch',
'crypto',
'navigator',
];
assert.deepStrictEqual(new Set(Object.keys(global)), new Set(expected));
}
Expand Down
15 changes: 15 additions & 0 deletions test/parallel/test-navigator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
'use strict';

require('../common');
const assert = require('assert');

const is = {
number: (value, key) => {
assert(!Number.isNaN(value), `${key} should not be NaN`);
assert.strictEqual(typeof value, 'number');
},
};

is.number(+navigator.hardwareConcurrency, 'hardwareConcurrency');
is.number(navigator.hardwareConcurrency, 'hardwareConcurrency');
assert.ok(navigator.hardwareConcurrency > 0);

0 comments on commit b40f0c3

Please sign in to comment.