ProcessInterval.js

/**
 * Callback function for ProcessInterval to execute on each tick.
 *
 * @callback ProcessIntervalTickRequester
 * @param {number} dt - The time elapsed since the last tick in milliseconds.
 */

/**
 * @class Representing a loop process based on the setInterval (native JS method).
 */
class ProcessInterval {
  /**
   * Create a new ProcessInterval.
   *
   * @param {object} [options={}] - Options of the process.
   * @param {number} [options.fps=60] - Frame rate per second of the process.
   */
  constructor(options = {}) {
    /**
     * Frame rate per second of the process.
     *
     * @type {number}
     */
    this.fps = options.fps || 60;

    /**
     * Buffer of ProcessIntervalTickRequesters.
     *
     * @type {ProcessIntervalTickRequester[]}
     */
    this.tickRequesters = [];

    /**
     * If true, the process is paused and ProcessIntervalTickRequesters are not called.
     *
     * @type {boolean}
     */
    this.pause = false;
  }

  /**
   * Stop the process and clear all tick requesters.
   */
  stop() {
    // reset requesters
    clearInterval(this.interval);
    this.tickRequesters.length = 0;
    this.pause = false;
  }

  /**
   * Pause or resume the process.
   *
   * @param {boolean} value - The new pause state of the process.
   */
  setPause(value) {
    this.pause = value;
  }

  /**
   * Add a new ProcessIntervalTickRequester to the list.
   *
   * @param {ProcessIntervalTickRequester} cb - The ProcessIntervalTickRequester to add.
   */
  addtickRequester(cb) {
    this.tickRequesters.push(cb);
  }

  /**
   * Start the process and call the tick function on each interval.
   *
   * @param {ProcessIntervalTickRequester=} requester - Optional default ProcessIntervalTickRequester.
   */
  start(requester) {
    if (requester) this.addtickRequester(requester);

    let lastTimeTick = 0;

    /**
     * The tick function called on each interval.
     */
    const tick = () => {
      const now = Date.now();
      let dt = 0;
      if (lastTimeTick) dt = now - lastTimeTick;
      lastTimeTick = now;

      if (this.pause) return;

      this.tickRequesters.forEach((cb) => {
        cb(dt);
      });
    };

    this.interval = setInterval(tick, 1000 / this.fps);
  }
}

module.exports = ProcessInterval;