Source: regularly.js

"use strict";

const noop = require("lodash.noop");

/**
 * Returns a function that starts calling λ repeatedly with an `interval` time interval.
 * That function has a stop() method to stop the loop. To resume the loop, make another
 * call to that function.
 *
 * @function regularly
 *
 * @param λ            {Function}       The function to call repeatedly.
 * @param interval     {Number}         The repetition interval.
 * @param errorHandler {Function|Falsy} A function to call when λ throws. By default, this is a noop.
 *
 * @return {Function} λ transformed into a loop control function that returns a
                      promise resolved after the first λ run and requiring no argument.
 */
module.exports = (λ, interval, errorHandler = noop) => {
    let timeoutId  = null;
    let promise    = null;
    let stop       = false;
    let λisRunning = false;

    const pollλ = () => {
        if (λisRunning) {
            return promise;
        }

        stop       = false;
        λisRunning = true;

        clearTimeout(timeoutId);

        return Promise
        .resolve()
        .then(λ)
        .catch(errorHandler)
        .catch(noop)
        .then(() => {
            λisRunning = false;

            if (!stop) {
                timeoutId = setTimeout(pollλ, interval);
            }
        });
    };

    pollλ.stop = () => {
        stop = true;

        clearTimeout(timeoutId);
    };

    return pollλ;
};