mostly fix node:timers

This commit is contained in:
Jarred Sumner
2023-01-31 17:51:36 -08:00
parent b7816f3175
commit b09896f06e
3 changed files with 105 additions and 24 deletions

View File

@@ -10,11 +10,18 @@
*/
declare module "timers" {
class Timer {
ref(): void;
unref(): void;
hasRef(): boolean;
}
const _exported: {
clearTimeout: typeof clearTimeout;
clearInterval: typeof clearInterval;
setTimeout: typeof setTimeout;
setInterval: typeof setInterval;
clearTimeout: (timer: Timer | number) => void;
clearInterval: (timer: Timer | number) => void;
setInterval: (cb: CallableFunction, msDelay: number, ...args: any[]) => Timer;
setTimeout: (cb: CallableFunction, msDelay: number, ...args: any[]) => Timer;
setImmediate: (cb: CallableFunction, ...args: any[]) => Timer;
};
export = _exported;
}

View File

@@ -1,3 +1,7 @@
// This implementation isn't 100% correct
// Ref/unref does not impact whether the process is kept alive
var clear = Symbol("clear");
class Timeout {
#id;
#refCount = 1;
@@ -17,6 +21,15 @@ class Timeout {
return this.#refCount > 0;
}
[clear]() {
this.#refCount = 0;
var clearFunction = this.#clearFunction;
if (clearFunction) {
this.#clearFunction = null;
clearFunction(this.#id);
}
}
unref() {
this.#refCount -= 1;
var clearFunction = this.#clearFunction;
@@ -26,23 +39,78 @@ class Timeout {
}
}
}
export const setInterval = globalThis.setInterval;
export const setImmediate = globalThis.queueMicrotask;
export const setTimeout = globalThis.setTimeout;
export const clearInterval = globalThis.clearInterval;
var {
setTimeout: setTimeout_,
setImmediate: setImmediate_,
clearTimeout: clearTimeout_,
setInterval: setInterval_,
clearInterval: clearInterval_,
} = globalThis;
// not implemented
export const clearImmediate = () => {};
export function setImmediate(callback, ...args) {
if (typeof callback !== "function") {
throw new TypeError("callback must be a function");
}
var cleared = false;
function clearImmediate(id) {
cleared = true;
}
export const clearTimeout = globalThis.clearTimeout;
export const queueMicrotask = globalThis.queueMicrotask;
const wrapped = function (callback, args) {
if (cleared) {
return;
}
cleared = true;
try {
callback(...args);
} catch (e) {
reportError(e);
} finally {
}
};
return new Timeout(setImmediate_(wrapped, callback, args), clearImmediate);
}
export function setTimeout(callback, delay, ...args) {
if (typeof callback !== "function") {
throw new TypeError("callback must be a function");
}
return new Timeout(setTimeout_.apply(globalThis, arguments), clearTimeout_);
}
export function setInterval(callback, delay, ...args) {
if (typeof callback !== "function") {
throw new TypeError("callback must be a function");
}
return new Timeout(setInterval_.apply(globalThis, arguments), clearInterval_);
}
export function clearTimeout(id) {
if (id && typeof id === "object" && id[clear]) {
id[clear]();
return;
}
clearTimeout_(id);
}
export function clearInterval(id) {
if (id && typeof id === "object" && id[clear]) {
id[clear]();
return;
}
clearInterval_(id);
}
export default {
setInterval,
queueMicrotask,
setImmediate,
setTimeout,
clearInterval,
clearImmediate,
clearTimeout,
[Symbol.for("CommonJS")]: 0,
};

View File

@@ -1,11 +1,17 @@
import { test } from "bun:test";
import { setTimeout } from "node:timers";
import { describe, test } from "bun:test";
import { setTimeout, clearTimeout, setInterval, setImmediate } from "node:timers";
// not implemented yet
// test("unref is possible", () => {
// const timer = setTimeout(() => {
// throw new Error("should not be called");
// }, 1000);
// timer.unref();
// clearTimeout(timer);
// });
for (const fn of [setTimeout, setInterval, setImmediate]) {
describe(fn.name, () => {
test("unref is possible", done => {
const timer = fn(() => {
done(new Error("should not be called"));
}, 1);
fn(() => {
done();
}, 2);
timer.unref();
if (fn !== setImmediate) clearTimeout(timer);
});
});
}