summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
author/usr/bin/cat <109351887+cu8code@users.noreply.github.com>2024-11-16 20:31:19 +0530
committerGitHub <noreply@github.com>2024-11-16 16:01:19 +0100
commit8d2960d7ccb756de4260a642d960cd01eaaa2478 (patch)
treea154005f17ef3540df7143b8f0b56c947987d624 /ext
parentabf06eb87f10ebed93b39948213dccfe086bd0fa (diff)
fix(ext/node): New async setInterval function to improve the nodejs compatibility (#26703)
Closes #26499
Diffstat (limited to 'ext')
-rw-r--r--ext/node/polyfills/timers.ts88
1 files changed, 86 insertions, 2 deletions
diff --git a/ext/node/polyfills/timers.ts b/ext/node/polyfills/timers.ts
index 02f69466e..e826416ed 100644
--- a/ext/node/polyfills/timers.ts
+++ b/ext/node/polyfills/timers.ts
@@ -15,10 +15,16 @@ import {
setUnrefTimeout,
Timeout,
} from "ext:deno_node/internal/timers.mjs";
-import { validateFunction } from "ext:deno_node/internal/validators.mjs";
+import {
+ validateAbortSignal,
+ validateBoolean,
+ validateFunction,
+ validateObject,
+} from "ext:deno_node/internal/validators.mjs";
import { promisify } from "ext:deno_node/internal/util.mjs";
export { setUnrefTimeout } from "ext:deno_node/internal/timers.mjs";
import * as timers from "ext:deno_web/02_timers.js";
+import { AbortError } from "ext:deno_node/internal/errors.ts";
const clearTimeout_ = timers.clearTimeout;
const clearInterval_ = timers.clearInterval;
@@ -89,10 +95,88 @@ export function clearImmediate(immediate: Immediate) {
clearTimeout_(immediate._immediateId);
}
+async function* setIntervalAsync(
+ after: number,
+ value: number,
+ options: { signal?: AbortSignal; ref?: boolean } = { __proto__: null },
+) {
+ validateObject(options, "options");
+
+ if (typeof options?.signal !== "undefined") {
+ validateAbortSignal(options.signal, "options.signal");
+ }
+
+ if (typeof options?.ref !== "undefined") {
+ validateBoolean(options.ref, "options.ref");
+ }
+
+ const { signal, ref = true } = options;
+
+ if (signal?.aborted) {
+ throw new AbortError(undefined, { cause: signal?.reason });
+ }
+
+ let onCancel: (() => void) | undefined = undefined;
+ let interval: Timeout | undefined = undefined;
+ try {
+ let notYielded = 0;
+ let callback: ((value?: object) => void) | undefined = undefined;
+ let rejectCallback: ((message?: string) => void) | undefined = undefined;
+ interval = new Timeout(
+ () => {
+ notYielded++;
+ if (callback) {
+ callback();
+ callback = undefined;
+ rejectCallback = undefined;
+ }
+ },
+ after,
+ [],
+ true,
+ ref,
+ );
+ if (signal) {
+ onCancel = () => {
+ clearInterval(interval);
+ if (rejectCallback) {
+ rejectCallback(signal.reason);
+ callback = undefined;
+ rejectCallback = undefined;
+ }
+ };
+ signal.addEventListener("abort", onCancel, { once: true });
+ }
+ while (!signal?.aborted) {
+ if (notYielded === 0) {
+ await new Promise((resolve: () => void, reject: () => void) => {
+ callback = resolve;
+ rejectCallback = reject;
+ });
+ }
+ for (; notYielded > 0; notYielded--) {
+ yield value;
+ }
+ }
+ } catch (error) {
+ if (signal?.aborted) {
+ throw new AbortError(undefined, { cause: signal?.reason });
+ }
+ throw error;
+ } finally {
+ if (interval) {
+ clearInterval(interval);
+ }
+ if (onCancel) {
+ signal?.removeEventListener("abort", onCancel);
+ }
+ }
+}
+
export const promises = {
setTimeout: promisify(setTimeout),
setImmediate: promisify(setImmediate),
- setInterval: promisify(setInterval),
+ setInterval: setIntervalAsync,
};
promises.scheduler = {