JSFiddle - React, Tailwind, and code Playground

by NOVUSIDEA

HTML

<link href="https://unpkg.com/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
<div id="quote" class="p-5"></div>

JavaScript

class SmartInterval {
  constructor(duration, callback, ...args) {
    this.duration = duration;
    this.callback = callback;
    this.args = args;

    this.timer = null;
    this.baseline = null;
    this.isRunning = false;

    this.handleVisibilityChange = this.handleVisibilityChange.bind(this);

    this.hiddenProp = null;
    this.visibilityEvent = null;

    if (typeof document.hidden !== "undefined") {
      this.hiddenProp = "hidden";
      this.visibilityEvent = "visibilitychange";
    } else if (typeof document.msHidden !== "undefined") {
      this.hiddenProp = "msHidden";
      this.visibilityEvent = "msvisibilitychange";
    } else if (typeof document.webkitHidden !== "undefined") {
      this.hiddenProp = "webkitHidden";
      this.visibilityEvent = "webkitvisibilitychange";
    }

    this.run();
  }

  get isWindowFocused() {
    return this.hiddenProp ? document[this.hiddenProp] : false;
  }

  run() {
    if (this.isRunning) return;
    this.isRunning = true;

    if (this.visibilityEvent) {
      document.addEventListener(
        this.visibilityEvent,
        this.handleVisibilityChange,
      );
    }

    if (!this.isWindowFocused) {
      this.start();
    }
  }

  start() {
    this.baseline = Date.now();

    const loop = () => {
      if (!this.isRunning || this.isWindowFocused) return;

      this.callback(...this.args);

      const end = Date.now();
      this.baseline += this.duration;

      let nextTick = this.duration - (end - this.baseline);
      if (nextTick < 0) nextTick = 0;

      this.timer = setTimeout(loop, nextTick);
    };

    loop();
  }

  stop() {
    this.isRunning = false;
    clearTimeout(this.timer);
    this.timer = null;
    if (this.visibilityEvent) {
      document.removeEventListener(
        this.visibilityEvent,
        this.handleVisibilityChange,
      );
    }
  }

  handleVisibilityChange() {
    if...