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...