Skip to content

Instantly share code, notes, and snippets.

@ryanvazquez
Last active April 15, 2022 16:22
Show Gist options
  • Save ryanvazquez/3f37d1a23ad1e0d5dc7df449ad96079a to your computer and use it in GitHub Desktop.
Save ryanvazquez/3f37d1a23ad1e0d5dc7df449ad96079a to your computer and use it in GitHub Desktop.
Simple utility for creating variadic intervals
// setIntervalTimeout sits somewhere between setTimeout and setInterval,
// allowing a finite or infinite number of fixed or variadic intervals.
// Returns a cleanup function to clear the current timeout.
// Note: IE does not support generators.
function setIntervalTimeout(callback, iterable, ...args){
if (!(Symbol.iterator in iterable)){
throw new Error(`Expected valid iterable. Received: ${iterable}.`);
}
let timeout = null;
function iterate(itr){
const next = itr.next();
if (!next.done){
timeout = setTimeout(() => {
callback(...args);
iterate(itr);
}, next.value);
}
}
iterate(iterable[Symbol.iterator]());
return () => clearTimeout(timeout);
}
// Bad:
setIntervalTimeout(console.log, { time: 1000 }, "Hello, world!"); // objects are not iterables
setIntervalTimeout(console.log, 1000, "Hello, world!"); // numbers are not iterables, use setTimeout instead.
// Weird:
// strings are iterable and valid timeout values. Will execute once, immediately, for each char.
setIntervalTimeout(console.log, "foobar", "Hello, world!");
// arrays are iterable but values are invalid timeout values. Will execute once, immediately, for each element.
setIntervalTimeout(console.log, [{foo: "foo"}], "Hello, world!");
// Unlikely - Maps, Sets, WeakMaps, etc:
setIntervalTimeout(console.log, new Map([1000, 1000]), "Hello, world!");
setIntervalTimeout(console.log, new Set([1000, 1000]), "Hello, world!");
setIntervalTimeout(console.log, new WeakMap([1000, 1000]), "Hello, world!");
// Arrays:
// Most of the time you will use an array of numbers.
setIntervalTimeout(console.log, [500], "Hello, world!"); // identical to setTimeout
setIntervalTimeout(console.log, [500, 500], "Hello, world!"); // identical to cancelling setInterval after two fixed intervals.
setIntervalTimeout(console.log, [500, 750, 1000], "Hello, world!"); // Three custom intervals.
// ...but you can technically use strings since JS will coerce them to numbers but don't do this.
setIntervalTimeout(console.log, ["500", "500"], "Hello, world!");
// Iterators:
// Useful for creating intervals programatically
const exponentialBackoff = function* generateFib(){
let a = 0, b = 1;
while (Number.isSafeInteger(a + b)){
const c = a + b;
a = b, b = c;
yield c;
}
}() //intervals increase exponentially - useful when retrying a failed network request
const linearBackoff = function* generateLinear(ms, start = 0){
let next = start;
while (Number.isSafeInteger(next + ms)) {
next += ms;
yield next;
}
}(500); // intervals increase linearly - useful for less aggressive backoffs
setIntervalTimeout(console.log, exponentialBackoff, "Retrying IMMEDIATELY RIGHT NOW...");
setIntervalTimeout(console.log, linearBackoff, "Retrying at a leisurely pace...");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment