Skip to content

Instantly share code, notes, and snippets.

@dotproto
Created November 14, 2024 02:14
Show Gist options
  • Save dotproto/c140e7a53edb0901c81ab2f85252f701 to your computer and use it in GitHub Desktop.
Save dotproto/c140e7a53edb0901c81ab2f85252f701 to your computer and use it in GitHub Desktop.
timeout()

timeout() is a promise-based version of setTimeout() with AbortSignal support.

function timeout(duration, {cb = ()=>{}, signal} = {}) {
return new Promise((resolve, reject) => {
signal?.throwIfAborted();
let timerId;
const handleAbort = () => {
clearTimeout(timerId);
reject(signal?.reason);
};
signal?.addEventListener("abort", handleAbort, {once: true});
timerId = setTimeout(() => {
signal?.removeEventListener("abort", handleAbort);
resolve(cb());
}, duration);
});
}
console.groupCollapsed("test 1")
var response = await timeout(100);
console.assert(response === undefined, {expected: undefined, received: response});
console.groupEnd();
console.groupCollapsed("test 2");
var response = await timeout(100, {cb: () => "normal"});
console.assert(response === "normal", {expected: "normal", received: response});
console.groupEnd();
console.groupCollapsed("test 3");
var controller = new AbortController();
var signal = controller.signal;
setTimeout(() => controller.abort("I felt like it"), 100);
try {
console.log(await timeout(1000, {signal}));
} catch (e) {
console.assert(e === "I felt like it", {expected: "I felt like it", received: e});
}
console.groupEnd();
console.groupCollapsed("test 4");
console.log("Creating abort controller");
var controller = new AbortController();
var signal = controller.signal;
console.log("Scheduling controller abort in 100ms");
setTimeout(() => {
console.log("aborting");
controller.abort("I felt like it")
}, 100);
try {
console.log("Scheduling `timeout` in 1000ms with the abort signal");
console.log(await timeout(1000, {cb: () => "normal", signal}));
} catch (e) {
console.log("Promise abort caught:", e);
console.assert(e, "I felt like it");
}
console.groupEnd();
console.groupCollapsed("test 5");
console.log("Creating abort controller");
var controller = new AbortController();
var signal = controller.signal;
console.log("Aborting immediately");
controller.abort("I have my reasons");
try {
console.log("Scheduling `timeout` in 1000ms with the abort signal");
console.log(await timeout(1000, {cb: () => "normal", signal}));
console.assert(false, "Should not have reached this line")
} catch(e) {
console.log("Promise abort caught:", e);
console.assert(e == "I have my reasons", {expected: "I have my reasons", received: e});
}
console.groupEnd();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment