Last active
February 9, 2018 01:29
-
-
Save joedski/201850f0dff080350778db95fdec7dac to your computer and use it in GitHub Desktop.
Simple function to repeat a call until a certain condition is met.
This file contains hidden or 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
// like repeatUntil but defers actual execution until explicitly called. | |
// Allows the use of different until conditions, or none at all. (repeat until explicitly canceled.) | |
function repeater({ interval, repeat }) { | |
let isCanceled = false; | |
let until; | |
function cancel() { | |
isCanceled = true; | |
} | |
function conditionallyCancel() { | |
if (until()) { | |
cancel(); | |
} | |
} | |
function repeatUntil(nextUntil) { | |
// If called with a new until condition, use the new one. | |
until = nextUntil; | |
// Swallow double calls. | |
if (!isCanceled) return; | |
isCanceled = false; | |
function callRepetition() { | |
// NOTE: Uncommenting this would result in 0 calls if until() immediately evaluates to true. | |
// conditionallyCancel(); | |
// | |
// if (isCanceled) return; | |
const callTime = Date.now(); | |
return Promise.resolve(repeat()) | |
.then(() => { | |
conditionallyCancel(); | |
if (isCanceled) return; | |
const delta = Date.now() - callTime; | |
// If we took longer, then repeat immediately. | |
if (delta >= interval) { | |
callRepetition(); | |
return; | |
} | |
// Otherwise, wait the remaining time. | |
setTimeout(() => { | |
conditionallyCancel(); | |
if (isCanceled) return; | |
callRepetition(); | |
}, interval - delta); | |
}) | |
// Swallowing errors. | |
.catch((error) => { | |
cancel(); | |
console.error('Error in repeateUntil:', error); | |
}) | |
; | |
} | |
callRepetition(); | |
} | |
function repeatUntilCanceled() { | |
repeatUntil(() => false); | |
} | |
return { | |
cancel, | |
repeat: repeatUntilCanceled, | |
repeatUntil, | |
}; | |
} |
This file contains hidden or 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
function repeatUntil({ interval, repeat, until }) { | |
// let callTime; | |
let isCanceled = false; | |
function cancel() { | |
isCanceled = true; | |
} | |
function conditionallyCancel() { | |
if (until()) { | |
cancel(); | |
} | |
} | |
function callRepetition() { | |
// NOTE: Uncommenting this would result in 0 calls if until() immediately evaluates to true. | |
// conditionallyCancel(); | |
// | |
// if (isCanceled) return; | |
const callTime = Date.now(); | |
return Promise.resolve(repeat()) | |
.then(() => { | |
conditionallyCancel(); | |
if (isCanceled) return; | |
const delta = Date.now() - callTime; | |
// If we took longer, then repeat immediately. | |
if (delta >= interval) { | |
callRepetition(); | |
return; | |
} | |
// Otherwise, wait the remaining time. | |
setTimeout(() => { | |
conditionallyCancel(); | |
if (isCanceled) return; | |
callRepetition(); | |
}, interval - delta); | |
}) | |
// Swallowing errors. | |
.catch((error) => { | |
cancel(); | |
console.error('Error in repeateUntil:', error); | |
}) | |
; | |
} | |
callRepetition(); | |
return { | |
cancel, | |
}; | |
} | |
module.exports = repeatUntil; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment