/* `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; };