Skip to content

Instantly share code, notes, and snippets.

@bb010g
Created October 14, 2022 02:18
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bb010g/73bc05fa880f89b127633ae532430863 to your computer and use it in GitHub Desktop.
Save bb010g/73bc05fa880f89b127633ae532430863 to your computer and use it in GitHub Desktop.
JavaScript/TypeScript `withInterval`
export class IntervalCancelledError extends Error {
constructor(intervalCount, ...args) {
super(...args);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, IntervalCancelledError);
}
this.name = "IntervalCancelledError";
this.intervalCount = intervalCount;
}
}
export function withInterval(promiseFunc, delay) {
let nextIntervalQueue = [];
const nextInterval = function () {
return new Promise(function (resolve, reject) {
nextIntervalQueue.push([resolve, reject]);
});
};
let intervalCount = 0;
const intervalCallback = function () {
for (const [resolve, _reject] of nextIntervalQueue) {
resolve(intervalCount);
}
nextIntervalQueue.length = 0;
++intervalCount;
};
const intervalId = setInterval(intervalCallback, delay);
const promise = promiseFunc(nextInterval);
const resolvedPromise = Promise.resolve(promise);
const onPromiseFufilled = function (_value) {
clearInterval(intervalId);
const intervalCancelledError = new IntervalCancelledError(
intervalCount,
"Promise fufilled"
);
intervalCancelledError.promise = resolvedPromise;
for (const [_resolve, reject] of nextIntervalQueue) {
reject(intervalCancelledError);
}
nextIntervalQueue.length = 0;
};
const onPromiseRejected = function (reason) {
clearInterval(intervalId);
const intervalCancelledError = new IntervalCancelledError(
intervalCount,
"Promise rejected",
{ cause: reason }
);
intervalCancelledError.promise = resolvedPromise;
for (const [_resolve, reject] of nextIntervalQueue) {
reject(intervalCancelledError);
}
nextIntervalQueue.length = 0;
};
resolvedPromise.then(onPromiseFufilled, onPromiseRejected);
return promise;
}
export class IntervalCancelledError extends Error {
public intervalCount: number;
public promise?: Promise<unknown>;
constructor(
intervalCount: number,
...args: ConstructorParameters<typeof Error>
) {
super(...args);
if (Error.captureStackTrace) {
Error.captureStackTrace(this, IntervalCancelledError);
}
this.name = "IntervalCancelledError";
this.intervalCount = intervalCount;
}
}
export function withInterval<
TResult,
TPromise extends TResult | PromiseLike<TResult>
>(
promiseFunc: (nextInterval: () => Promise<number>) => TPromise,
delay: number
): TPromise {
let nextIntervalQueue: [
(value: number | PromiseLike<number>) => void,
(reason?: unknown) => void
][] = [];
const nextInterval = function (): Promise<number> {
return new Promise(function (resolve, reject): void {
nextIntervalQueue.push([resolve, reject]);
});
};
let intervalCount: number = 0;
const intervalCallback = function (): void {
for (const [resolve, _reject] of nextIntervalQueue) {
resolve(intervalCount);
}
nextIntervalQueue.length = 0;
++intervalCount;
};
const intervalId = setInterval(intervalCallback, delay);
const promise: TPromise = promiseFunc(nextInterval);
const resolvedPromise: Promise<TResult> = Promise.resolve<TResult>(promise);
const onPromiseFufilled = function (_value: TResult): void {
clearInterval(intervalId);
const intervalCancelledError = new IntervalCancelledError(
intervalCount,
"Promise fufilled"
);
intervalCancelledError.promise = resolvedPromise;
for (const [_resolve, reject] of nextIntervalQueue) {
reject(intervalCancelledError);
}
nextIntervalQueue.length = 0;
};
const onPromiseRejected = function (reason: unknown): void {
clearInterval(intervalId);
const intervalCancelledError = new IntervalCancelledError(
intervalCount,
"Promise rejected",
{ cause: reason }
);
intervalCancelledError.promise = resolvedPromise;
for (const [_resolve, reject] of nextIntervalQueue) {
reject(intervalCancelledError);
}
nextIntervalQueue.length = 0;
};
resolvedPromise.then(onPromiseFufilled, onPromiseRejected);
return promise;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment