Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJames M Snell <jasnell@gmail.com>2020-06-18 23:22:17 +0300
committerJames M Snell <jasnell@gmail.com>2020-06-23 00:29:49 +0300
commita8904e8eeea3ca513de588424bb99f6a7cdfc598 (patch)
tree35d9fc741714a1c71939b91c9b8ef69cdbf65f4c /lib/timers
parentbfc0e3f0b0bc99deffe99586bd9f03a27c6ed098 (diff)
timers: introduce timers/promises
Move the promisified timers implementations into a new sub-module to avoid the need to promisify. The promisified versions now return the timers/promises versions. Also adds `ref` option to the promisified versions ```js const { setTimeout, setImmediate } = require('timers/promises'); setTimeout(10, null, { ref: false }) .then(console.log); setImmediate(null, { ref: false }) .then(console.log); ``` Signed-off-by: James M Snell <jasnell@gmail.com> PR-URL: https://github.com/nodejs/node/pull/33950 Reviewed-By: Denys Otrishko <shishugi@gmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com>
Diffstat (limited to 'lib/timers')
-rw-r--r--lib/timers/promises.js124
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/timers/promises.js b/lib/timers/promises.js
new file mode 100644
index 00000000000..78197fe86f6
--- /dev/null
+++ b/lib/timers/promises.js
@@ -0,0 +1,124 @@
+'use strict';
+
+const {
+ Promise,
+ PromiseReject,
+} = primordials;
+
+const {
+ Timeout,
+ Immediate,
+ insert
+} = require('internal/timers');
+
+const {
+ hideStackFrames,
+ codes: { ERR_INVALID_ARG_TYPE }
+} = require('internal/errors');
+
+let DOMException;
+
+const lazyDOMException = hideStackFrames((message) => {
+ if (DOMException === undefined)
+ DOMException = internalBinding('messaging').DOMException;
+ return new DOMException(message);
+});
+
+function setTimeout(after, value, options = {}) {
+ const args = value !== undefined ? [value] : value;
+ if (options == null || typeof options !== 'object') {
+ return PromiseReject(
+ new ERR_INVALID_ARG_TYPE(
+ 'options',
+ 'Object',
+ options));
+ }
+ const { signal, ref = true } = options;
+ if (signal !== undefined &&
+ (signal === null ||
+ typeof signal !== 'object' ||
+ !('aborted' in signal))) {
+ return PromiseReject(
+ new ERR_INVALID_ARG_TYPE(
+ 'options.signal',
+ 'AbortSignal',
+ signal));
+ }
+ if (typeof ref !== 'boolean') {
+ return PromiseReject(
+ new ERR_INVALID_ARG_TYPE(
+ 'options.ref',
+ 'boolean',
+ ref));
+ }
+ // TODO(@jasnell): If a decision is made that this cannot be backported
+ // to 12.x, then this can be converted to use optional chaining to
+ // simplify the check.
+ if (signal && signal.aborted)
+ return PromiseReject(lazyDOMException('AbortError'));
+ return new Promise((resolve, reject) => {
+ const timeout = new Timeout(resolve, after, args, false, true);
+ if (!ref) timeout.unref();
+ insert(timeout, timeout._idleTimeout);
+ if (signal) {
+ signal.addEventListener('abort', () => {
+ if (!timeout._destroyed) {
+ // eslint-disable-next-line no-undef
+ clearTimeout(timeout);
+ reject(lazyDOMException('AbortError'));
+ }
+ }, { once: true });
+ }
+ });
+}
+
+function setImmediate(value, options = {}) {
+ if (options == null || typeof options !== 'object') {
+ return PromiseReject(
+ new ERR_INVALID_ARG_TYPE(
+ 'options',
+ 'Object',
+ options));
+ }
+ const { signal, ref = true } = options;
+ if (signal !== undefined &&
+ (signal === null ||
+ typeof signal !== 'object' ||
+ !('aborted' in signal))) {
+ return PromiseReject(
+ new ERR_INVALID_ARG_TYPE(
+ 'options.signal',
+ 'AbortSignal',
+ signal));
+ }
+ if (typeof ref !== 'boolean') {
+ return PromiseReject(
+ new ERR_INVALID_ARG_TYPE(
+ 'options.ref',
+ 'boolean',
+ ref));
+ }
+ // TODO(@jasnell): If a decision is made that this cannot be backported
+ // to 12.x, then this can be converted to use optional chaining to
+ // simplify the check.
+ if (signal && signal.aborted)
+ return PromiseReject(lazyDOMException('AbortError'));
+ return new Promise((resolve, reject) => {
+ const immediate = new Immediate(resolve, [value]);
+ if (!ref) immediate.unref();
+ if (signal) {
+ signal.addEventListener('abort', () => {
+ if (!immediate._destroyed) {
+ // eslint-disable-next-line no-undef
+ clearImmediate(immediate);
+ reject(lazyDOMException('AbortError'));
+ }
+ }, { once: true });
+ }
+ });
+}
+
+module.exports = {
+ setTimeout,
+ setImmediate,
+};