Source: observer/TimeObserver.js

(function() {
    /**
     * the types for TimeObserver.observe
     * @typedef {('timeout'|'interval')} Help4.observer.TimeObserver.Type
     */

    /**
     * the options for TimeObserver.observe
     * @typedef {Object} Help4.observer.TimeObserver.Options
     * @property {number} time - the time to wait
     * @property {Object} [data] - the information to be delivered after time
     */

    /**
     * observes time events
     * @augments Help4.observer.Observer
     */
    Help4.observer.TimeObserver = class extends Help4.observer.Observer {
        /**
         * Starts a timeout or an interval; delivers data on time
         * @override
         * @param {Help4.observer.TimeObserver.Type} target
         * @param {Help4.observer.TimeObserver.Options} options
         * @returns {Help4.observer.TimeObserver}
         */
        observe(target, options) {
            const fun = target === 'timeout' ? 'setTimeout' : 'setInterval';
            const connectionId = Help4.createId();
            const timerId = window[fun](() => _onTime.call(this, connectionId), options.time);

            this._connections.push({
                target,
                options,
                connectionId,
                timerId
            });
            return this;
        }

        /**
         * @override
         * @returns {Help4.observer.TimeObserver}
         */
        disconnect() {
            const {_connections} = this;

            let c, f;
            while (c = _connections.shift()) {
                f = c.target === 'timeout' ? 'clearTimeout' : 'clearInterval';
                window[f](c.timerId);
            }
            return this;
        }
    }

    /**
     * a timeout/interval is reached; execute callback with data
     * @memberof Help4.observer.TimeObserver#
     * @param {string} connectionId
     * @private
     */
    function _onTime(connectionId) {
        const {_connections} = this;

        for (const [i, c] of Help4.arrayEntries(_connections)) {
            if (c.connectionId === connectionId) {
                if (c.target === 'timeout') _connections.splice(i, 1);
                this._callback(c.options.data);
                return;
            }
        }
    }
})();