Repeat or retry a function call until it returns a specific value or a timeout is reached.
Created for handling / observing intermediate or final states of asynchronous processes (see Details), but also helpful for other things (see Examples).
hh lohmann <hh.lohmann@gmail.com>
This page may be displayed more optimal in its GitHub Pages view
import { repeatFunctionCallTimer } from 'repeat-function-call-timer'
repeatFunctionCallTimer( functionToCall, expectedValue, timeout, interval )
await repeatFunctionCallTimer( functionToCall, expectedValue, timeout, interval )
const res = await repeatFunctionCallTimer( functionToCall, expectedValue, timeout, interval )
if(res.match) ...
repeatFunctionCallTimer( functionToCall, expectedValue, timeout, interval )
.then(res=>{
if(res.match){ ... }
else{ ... }
})
repeatFunctionCallTimer( functionToCall, expectedValue, timeout, interval, whenInterval )Function to repeat
- Returning a target value that allows matching expectedValue to exit repetition
- Use no or an intentionally unmatchable return to exit on timeout only
- Intentionally left to be defined in detail by individual use cases to gain maximum flexibility
- Intentionally no parameters
- Parameters may introduce complexity that might not be easy to control
- You may use whenInterval to manipulate an external environment at runtime to be listened to by functionToCall
- Can not be an asynchronous function / Promise or a function returning an asynchronous function / Promise since it runs synchronously to points in time resulting from defined interval, but is intended to be usable as an observer for asynchronous functions / Promises (see Details / Examples)
Value to compare with return of functionToCall to exit repetition
- Can only be a Primitive Type (except Symbol), i.e. null or of type bigint / boolean / number / string / undefined
- For working with Arrays, Errors, Functions, Objects, Maps or RegExps you would use a wrapper functionToCall with an own comparison method returning true or false
- Use an intentionally unmatchable value to exit on timeout only
Timespan in milliseconds to repeat functionToCall to match expectedValue before giving up
- Use no or an intentionally unmatchable return of functionToCall or an intentionally unmatchable value to exit on timeout only
Timespan in milliseconds to wait before next repetition
optional: Callback on start of new interval
- Hook for injecting actions
- Parameter:
passedTime: The time passed since start. May be used for analyses. - Note: Does not allow to manipulate internal parameters at runtime, but you may manipulate an external environment to be listened to by functionToCall
-
Do something only if an observed process set a value
function observerFunction(){ // ... code to check if observed value has been set by observed process ... if(observedValueHasBeenSet) return true; return false; } const res = await repeatFunctionCallTimer( observerFunction, true, 2000, 100 ) if(res.match){ // ... something only if value was set in given time }
-
Do different things depending if another asynchronous process set a value
function observerFunction(){ // ... code to check if observed value has been set by observed process ... if(observedValueHasBeenSet) return true; return false; } repeatFunctionCallTimer( observerFunction, true, 2000, 100 ) .then(res=>{ if(res.match){ // ... something only if value was set in given time } else{ // ... something if value was no set in given time } })
-
Tracking an observed process that sets trackable values
function observerFunction(){ // ... code to check current values set by observed process ... if(observedValue==='reading') return console.log('Reading data...'); if(observedValue==='processing') return console.log('Processing data...'); if(observedValue==='writing') return console.log('Writing data...'); if(observedValue==='fail') return 'finished'; if(observedValue==='success') return 'finished'; return 'unknown'; } const res = await repeatFunctionCallTimer( observerFunction, 'finished', 2000, 100 ) .then(res=>{ if(res.match){ console.log(`Process XY finished - see XY's own output for details`) } else{ console.log(`Process XY did not finish in expected time`) } })
-
Log current time's seconds while doing something else
repeatFunctionCallTimer( ()=>console.log(new Date().getSeconds()), '', 3000, 1000 ); // ... meanwhile something else ...
-
Log current time's seconds before doing something else
await repeatFunctionCallTimer( ()=>console.log(new Date().getSeconds()), '', 3000, 1000 ); // ... afterwards something else ...
See demos on GitHub Pages for this repo
-
Be aware that timers in JavaScript are not exact, depending e.g. on the current Call stack. They are reliable for "normal" checking and ordering, but not for high precision orchestration which is clearly not the scope here
-
The functionToCall itself can not be an asynchronous function / Promise or a function returning an asynchronous function / Promise since it runs synchronously to points in time resulting from defined interval, but is intended to be usable as an observer for asynchronous functions / Promises (see Examples)
Pick for your preferred package manager:
npm i repeat-function-call-timer pnpm i repeat-function-call-timer bun i repeat-function-call-timer # For Yarn you should double check docs for your and / or
# current Yarn version, newer versions do not treat `i package_name`
# as an alias for `add ...` and exclude global installations
yarn add repeat-function-call-timer-
Created primarily for handling / observing intermediate or final states of asynchronous processes, especially when there is no resolving to be handled with await or .then(), but the possibility to write to a variable that can be observed by a simple functionToCall. If
then()/awaitis available, the defined timeout can intercept if athen()/awaitthat would set the observed variable takes too long. Using separatetly started processes communicating via an observed variable instead of e.g. one process starting another process for observing it should guarantee simplicity, flexibility and robustness. -
Besides observing other processes (see above) also usable for plain repetition of an arbitrary function until an arbitrary expectedValue is matched
-
Intentionally no parameter for "number of tries" / "maximum number of tries": Such parameters are dangerous without a timeout, otherwise you might wait forever (or until a system timeout) for a try without an answer, but you can always model a number of e.g. 10 tries by setting timeout as the 10th of interval
-
Implemented as a recursion of setTimeout calls that is terminated by timeout or matching expectedValue
- Code tests to be run with Node.js / Bun available in Source Code