Skip to content

Instantly share code, notes, and snippets.

@devsnek
Last active October 6, 2019 17:37
Show Gist options
  • Save devsnek/9686da77db0421927c84e862bd70b214 to your computer and use it in GitHub Desktop.
Save devsnek/9686da77db0421927c84e862bd70b214 to your computer and use it in GitHub Desktop.
// simple timer
await TimerThing.delay(n, { signal });
// simple interval
const interval = TimerThing.repeat(n, { signal });
for await (const _ of interval) {
if (condition) controller.abort();
if (condition2) break;
}
// instance of TimerThing can track multiple timers, think of TimerThing statics as a singleton i guess
const wheel = new TimerThing({ signal });
const interval = wheel.repeat(n, { /* signal */ });
for await (const _ of interval) {
if (condition) controller.abort();
if (condition2) break;
}
// repeat and delay both return the same thing, delay is basically repeat that ends after 1
class TimerThing {
constructor({ signal } = {}) {
if (signal !== undefined) {
signal.addEventListener('abort', () => this.clear());
}
this.timers = new Set();
}
repeat(milliseconds, { limit, signal } = {}) {
if (limit === undefined) {
limit = Infinity;
}
const queue = [];
let done = false;
const interval = setInterval(() => {
queue.forEach((d) => {
d.resolve({ value: undefined, done: false });
});
queue.length = 0;
limit -= 1;
if (limit === 0) {
finish();
}
}, milliseconds);
const finish = () => {
if (done) {
return;
}
done = true;
clearInterval(interval);
queue.forEach((d) => {
d.resolve({ value: undefined, done: true });
});
queue.length = 0;
this.timers.delete(finish);
if (signal !== undefined) {
signal.removeEventListener('abort', finish);
}
};
if (signal !== undefined) {
signal.addEventListener('abort', finish);
}
this.timers.add(finish);
return {
[Symbol.asyncIterator]() { return this; },
then(thenableResolve, thenableReject) {
return this.next()
.then(({ done }) => {
if (done) {
return Promise.reject(new Error('timer is done'));
}
})
.then(thenableResolve, thenableReject);
},
next() {
if (done) {
return Promise.resolve({ value: undefined, done: true });
}
return new Promise((resolve, reject) => {
queue.push({ resolve, reject });
});
},
async return() {
finish();
},
};
}
delay(milliseconds, options) {
return this.repeat(milliseconds, { ...options, limit: 1 });
}
clear() {
this.timers.forEach((finish) => {
finish();
});
}
static repeat(...args) {
return singleton.repeat(...args);
}
static delay(...args) {
return singleton.delay(...args);
}
}
const singleton = new TimerThing();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment