/// An async wrapper around `setTimeout()` and `setInterval()`. /// /// # `setTimeout()` /// `await (new AsyncTimeout(() => "value", 100)).timeout() /* === "value" */` is `setTimeout(()=> "value", 100)` promisified. /// /// # `setInterval()` /// `for await (const value of new AsyncTimeout(() => "value", 100)).interval()) { /* value === "value" */ }` is `setInterval(()=> "value", 100)` promisified. /// This is an infinite iterator. To cancel the interval, simply break out of the `for await` loop. /// /// # Parameters /// * `thing` - The function to call after the timeout/interval. The result of the promise (or the yield for `interval()`) is the result of this function call. If the funtion throws, then the rejection of the promise will be that error thrown. /// * `interval` - The time to wait for the timeout or interval /// /// # Examples /// See `examples` below. function AsyncTimeout(thing, interval) { function isPromise(obj) { return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'; } async function _call(t) { if(isPromise(t)) return await t(arguments); else await (async () => {}); return t(arguments); } this.timeout = () => new Promise((resolve, reject) => { setTimeout(() => { try { _call(thing).then(resolve); //XXX: This design doesn't work, we'll need to go back to the drawing board with this function for this to work... The exception won't propagate here, so... } catch(e) { reject(e); } }, interval); }); this.interval = async function*() { while(true) { yield await new Promise((resolve, reject) => { setTimeout(() => { try { _call(thing).then(resolve); } catch(e) { reject(e); } }, interval); }); } }; } const example = async (_timeout) => { _timeout = _timeout || 100; // Wait 100 then alert "hi" console.log(await (new AsyncTimeout(() => "hi", _timeout)).timeout()); // Continuously wait 100 then alert "hi" for await (const value of new AsyncTimeout(() => "hi forever", _timeout).interval()) { console.log(value); } };