Utility function to cope with `interval` executing asynchronous call.
/* | |
`setInterval` triggers a function every X secs. | |
It's not satifying when you deal with asynchronous functions, such as API calls. | |
It is indeed possible that the response comes right before the next scheduled call, or even after, defeating the purpose of intervals. | |
The `interval` function below aims at solving this issue. | |
Usage: | |
// real life usage, used in a redux thunk | |
interval(() => bodymap.get(), { | |
// condition for early exit | |
exitIf({ status }) { return status && status !== 'pending' }, | |
// onSuccess handler | |
onSuccess(payload) { | |
dispatch(bodymapCreationSucceed(payload)); | |
}, | |
// onError handler | |
onError(error) { | |
dispatch(bodymapCreationFailed({ | |
id: payload.id, | |
error, | |
})); | |
}, | |
// onTimeout handler, triggered if `exitIf` hasn't been met after`maxIteration` tries | |
onTimeout() { | |
dispatch(failBodymapCreation({ | |
id: payload.id, | |
error: 'timeout', | |
})); | |
}, | |
// number max of iteration - triggers onTimeout handler if maxIteration reached | |
maxIteration: 12, | |
// time between 2 iterations (in milliseconds) | |
time: 5000, | |
}); | |
*/ | |
export const interval = (fn, props) => { | |
const { exitIf, onSuccess, onError, onTimeout, maxIteration, time } = props; | |
let intervalHandler = setTimeout(function () { | |
return fn() | |
.then(payload => { | |
const isExiting = exitIf(payload); | |
if (isExiting) { | |
return onSuccess(payload); | |
} | |
if (maxIteration > 1) { | |
intervalHandler = interval(fn, { ...props, maxIteration: maxIteration - 1 }); | |
return intervalHandler; | |
} | |
return onTimeout(); | |
}) | |
.catch(error => onError(error)); | |
}, time); | |
return intervalHandler; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment