diff --git a/.eslintrc.js b/.eslintrc.js index 3f47ddf45d0534..a6295e62987e87 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -331,5 +331,7 @@ module.exports = { globalThis: 'readable', btoa: 'readable', atob: 'readable', + requestAnimationFrame: 'readable', + cancelAnimationFrame: 'readable', }, }; diff --git a/doc/api/globals.md b/doc/api/globals.md index 831ef06bec6094..6ec441bfc020cf 100644 --- a/doc/api/globals.md +++ b/doc/api/globals.md @@ -164,6 +164,29 @@ added: REPLACEME Global alias for [`buffer.btoa()`][]. +## `cancelAnimationFrame(immediateObject)` + + + + +> Stability: 3 - Legacy: Use clearImmediate() instead. + +* `immediateObject` {Object} The return value of `requestAnimationFrame()` + identifying the request being canceled. + +```js +const req = requestAnimationFrame((ts) => { + console.log(`called at ${ts}`); +}); + +cancelAnimationFrame(req); +``` + +In Node.js, `cancelAnimationFrame()` is an alias for `clearImmediate()`. +Code specifically targeting Node.js should use `clearImmediate()` instead. + ## `clearImmediate(immediateObject)` + + + +> Stability: 3 - Legacy: Use the setImmediate() instead. + +* `callback` {Function} +* Returns {Object} + +Registers a function with `setImmediate()` that is invoked with a single +argument set to the value of `perf_hooks.performance.now()`. + +```js +requestAnimationFrame((ts) => { + console.log(`called at ${ts}`); +}); +``` + +Node.js does not implement the same timing and event loop frame semantics +as Web Browsers and does not include any notion of rendering or "animation". +The `requestAnimationFrame()` method should be considered a close approximation +to enable cross-environment portable JavaScript code to be written. Code +specifically targeting Node.js should use `setImmediate()` instead. + ## `require()` This variable may appear to be global but is not. See [`require()`][]. diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js index d8f5c18d12d79b..1cb017e7bb0c96 100644 --- a/lib/internal/bootstrap/node.js +++ b/lib/internal/bootstrap/node.js @@ -239,6 +239,20 @@ if (!config.noBrowserGlobals) { // Non-standard extensions: defineOperation(global, 'clearImmediate', timers.clearImmediate); defineOperation(global, 'setImmediate', timers.setImmediate); + + function requestAnimationFrame(callback) { + const { performance } = require('perf_hooks'); + const { + codes: { + ERR_INVALID_ARG_TYPE, + }, + } = require('internal/errors'); + if (typeof callback !== 'function') + throw new ERR_INVALID_ARG_TYPE('callback', 'Function', callback); + return timers.setImmediate(() => callback(performance.now())); + } + defineOperation(global, 'requestAnimationFrame', requestAnimationFrame); + defineOperation(global, 'cancelAnimationFrame', timers.clearImmediate); } // Set the per-Environment callback that will be called diff --git a/test/common/index.js b/test/common/index.js index 03eec756d0a19a..1dc41bdbb7be38 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -261,6 +261,8 @@ function platformTimeout(ms) { return ms; // ARMv8+ } +const requestAnimationFrame = globalThis.requestAnimationFrame; + let knownGlobals = [ atob, btoa, @@ -268,6 +270,7 @@ let knownGlobals = [ clearInterval, clearTimeout, global, + requestAnimationFrame, setImmediate, setInterval, setTimeout, diff --git a/test/parallel/test-requestanimationframe.js b/test/parallel/test-requestanimationframe.js new file mode 100644 index 00000000000000..160995a19c43ab --- /dev/null +++ b/test/parallel/test-requestanimationframe.js @@ -0,0 +1,16 @@ +'use strict'; + +const common = require('../common'); +const { strictEqual } = require('assert'); + +let called = false; + +requestAnimationFrame(common.mustCall((ts) => { + called = true; + strictEqual(typeof ts, 'number'); +})); + +strictEqual(called, false); + +const req = requestAnimationFrame(common.mustNotCall()); +cancelAnimationFrame(req);