Last active
January 15, 2020 00:49
-
-
Save robertpitt/cce38ec3996dc545b1c511f43864616b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Perform a async sleep operation, this is useful for testing | |
*/ | |
const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms)) | |
/** | |
* Debounce a async function call | |
*/ | |
const debounce = (fn, offsetMs = 0) => { | |
let timer = null | |
let resolves = [] | |
return (...props) => { | |
// If the function is called multiple times this clear timeout will | |
// reset the execution offset | |
clearTimeout(timer) | |
// We create a timer to execute the function at the offset | |
timer = setTimeout(() => { | |
// As the timeout called this callback, we can actually execute the request | |
const targetPromiseResult = fn.call(this, ...props) | |
// EHandle the resolvers | |
resolves.forEach(resolver => resolver(targetPromiseResult)) | |
resolves = [] | |
}, offsetMs) | |
return new Promise((resolve, reject) => resolves.push(resolve)) | |
} | |
} | |
/** | |
* Based on David Walsh's "JavaScript fetch with Timeout" | |
* @see {@link https://davidwalsh.name/fetch-timeout} | |
* | |
* @param {() => Promise} fn | |
* @param {number} [timeout] | |
* | |
* @returns {Promise} | |
*/ | |
const callWithTimeout = (fn, timeout) => { | |
let didTimeOut = false | |
return new Promise((resolve, reject) => { | |
const timer = | |
timeout && | |
setTimeout(() => { | |
didTimeOut = true | |
reject(new Error('Request timed out')) | |
}, timeout) | |
fn() | |
.then(response => { | |
// Clear the timeout as cleanup | |
clearTimeout(timer) | |
if (!didTimeOut) { | |
resolve(response) | |
} | |
}) | |
.catch(err => { | |
// Rejection already happened with setTimeout | |
if (didTimeOut) return | |
// Reject with error | |
reject(err) | |
}) | |
}) | |
} | |
/** | |
* Poll a Promiser Factory | |
* @param {object} options An options object | |
* @param {() => Promise} options.fn A promise | |
* @param {number} options.interval Time in ms representing the time span between the promise resolving and the next one firing | |
* @param {number} options.timeout The maximum amount of time in ms which the promise is allowed to take | |
* @param {(value: any) => any} options.onSuccess The success callback | |
* @param {(reason: any) => any} options.onError The error callback | |
* | |
* @returns {{start: () => void, stop: () => void}} | |
*/ | |
const pollable = ({ fn, interval, timeout, onSuccess, onError }) => { | |
let running = false | |
return { | |
/** | |
* Starts the interval | |
*/ | |
start: () => { | |
running = true; | |
(function run () { | |
callWithTimeout(fn, timeout) | |
.then(res => { | |
if (running) { | |
onSuccess(res) | |
sleep(interval).then(run) | |
} | |
}) | |
.catch(err => { | |
if (running) { | |
onError(err) | |
sleep(interval).then(run) | |
} | |
}) | |
})() | |
}, | |
/** | |
* Stops the interval | |
*/ | |
stop: () => { | |
running = false | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment