UNPKG

js-timers

Version:

包含定时器:浏览器中使用的定时器,通过补偿比setInterval更精准;倒计时定时器;(timer: Timer used in browser,More accurate than setInterval; count-down-timer;)

365 lines (297 loc) 10.3 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.$timers = {})); })(this, (function (exports) { 'use strict'; function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; } /** * Class: Timer */ var Timer = /*#__PURE__*/function () { function Timer() { this._interval = 1000; this._initInterval = 1000; this._tick; this._isTimerStop = false; //Whether is the immediately stop this.timer = null; this._startTime = null; this._tickCount = 0; this.missTickEnabled = false; //若延迟误差超过了间隔时间,则忽略miss掉中间,还是追加补偿tick this._delta = 0; //由于补偿后,在执行setTimeout时,仍会消耗1-2 ms导致1-2 ms误差,若还需要差量补偿,可以更改这个参数 } ///时间间隔(单位毫秒ms),默认1s var _proto = Timer.prototype; // --------- public 方法------------ _proto.start = function start() { this._isTimerStop = false; this._startTime = new Date().getTime(); clearTimeout(this.timer); this.startSetTimeout(); }; _proto.stop = function stop() { this._isTimerStop = true; this._tickCount = 0; clearTimeout(this.timer); } ///获取定时器是否停止状态 ; //----------------- private 方法--------------------- _proto.isFunction = function isFunction(func) { return func && Object.prototype.toString.call(func) === '[object Function]'; }; _proto.startSetTimeout = function startSetTimeout() { var _this = this; this.timer = setTimeout(function () { _this.tickEvent(); }, this._interval - this._delta); }; _proto.tickEvent = function tickEvent() { if (!this.isFunction(this._tick)) { this.stop(); throw new Error("tick:" + this._tick + ",tick is not function."); } if (!this._isTimerStop) { this._tickCount++; this.offsetDiff(); this.startSetTimeout(); this._tick(); } }; _proto.offsetDiff = function offsetDiff() { var offset = new Date().getTime() - (this._startTime + this._tickCount * this._initInterval); // console.log("误差:" + offset) //由于补偿后,在执行setTimeout时,仍会消耗1-2 ms导致1-2 ms误差, var nextTime = this._initInterval - offset; if (nextTime < 0 && this._missTickEnabled) { //若小于0,表示误差大于间隔,已经错过了一次tick,若错过tick,则应该排除多余的tick做补偿 this._interval = this._initInterval - Math.abs(nextTime) % this._initInterval; } else { this._interval = nextTime >= 0 ? nextTime : 0; } }; _createClass(Timer, [{ key: "interval", get: function get() { return this._initInterval; }, set: function set(seconds) { this._interval = seconds; this._initInterval = seconds; } //差量,因为setTimeout的js执行也需要时间,所以可以设置差量,达到最小误差. }, { key: "delta", get: function get() { return this._delta; }, set: function set(val) { this._delta = val; } ///时间定时器定时执行函数 }, { key: "tick", get: function get() { return this._tick(); }, set: function set(func) { if (!this.isFunction(func)) { throw new Error("tick is not function."); } this._tick = func; } }, { key: "missTickEnabled", get: function get() { return this._missTickEnabled; }, set: function set(val) { this._missTickEnabled = !!val; } }, { key: "isTimerStop", get: function get() { return this._isTimerStop; } }]); return Timer; }(); /** * Enum: Status */ var CountDownTimerStatus = Object.freeze({ //运行 running: 'running', //停止 stop: 'stop', //暂停 pause: 'pause' }); /** * Enum: Mode */ // const CountDownTimeoutMode = Object.freeze({ // loop: Symbol(0), // reset: Symbol(1) // }) var CountDownTimeoutMode = Object.freeze({ //Stop when the countdown is over once: 'once', //after the timer stop,restart loop: 'loop', //reset countdown after user operation reset: 'reset' }); /*倒计时类 */ var CountDownTimer = /*#__PURE__*/function () { function CountDownTimer() { var _this = this; this._remainingSeconds = 60; this._timeoutSeconds = 60; this._timerStatus = CountDownTimerStatus.pause; //操作定时状态 this._timeoutMode = CountDownTimeoutMode.once; // 操作超时模式 this.onTimeout = null; //超时触发器 this.tick = null; //倒计时触发器 this.mainTimer = new Timer(); this.mainTimer.interval = 1000; //主要定时器时间间隔 this.mainTimer.tick = function () { _this.mainTimerEvent(); }; } //超时剩余时间 var _proto = CountDownTimer.prototype; /*--------设置操作时间超时------[公有方法]----------------*/ _proto.setTimeout = function setTimeout(seconds) { this.stop(); this._timeoutSeconds = seconds; this._remainingSeconds = seconds; } //启动操作 ; _proto.start = function start() { // console.log(`CountDownTimer start: ${this.timeoutSeconds}s`); if (this._timeoutMode === CountDownTimeoutMode.reset) { this.listenActiveEvent(); } this._remainingSeconds = this._timeoutSeconds; this._timerStatus = CountDownTimerStatus.running; this.mainTimer.start(); } //监听用户操作激活 ; _proto.listenActiveEvent = function listenActiveEvent() { var _this2 = this; var body = document.querySelector('html'); var activeFun = function activeFun(event) { body.removeEventListener("click", activeFun); body.removeEventListener("keydown", activeFun); body.removeEventListener("mousemove", activeFun); body.removeEventListener("mousewheel", activeFun); _this2.reset(); }; body.addEventListener("click", activeFun); body.addEventListener("keydown", activeFun); body.addEventListener("mousemove", activeFun); body.addEventListener("mousewheel", activeFun); } //停止操作 ; _proto.stop = function stop() { this._remainingSeconds = 0; this._timerStatus = CountDownTimerStatus.stop; this.mainTimer.stop(); } //暂停操作 ; _proto.pause = function pause() { if (this._timerStatus == CountDownTimerStatus.running) { this._timerStatus = CountDownTimerStatus.pause; this.mainTimer.stop(); } } //恢复倒计时 ; _proto.resume = function resume() { if (this._timerStatus != CountDownTimerStatus.pause) { return; } this.mainTimer.start(); this._timerStatus = CountDownTimerStatus.running; } //重置倒计时 ; _proto.reset = function reset() { if (this._timerStatus === CountDownTimerStatus.stop) { return; } this.stop(); this.start(); } /*-----------------------------------------------*/ /*----倒计时定时器触发事件------[私有方法]----------*/ ; _proto.isFunction = function isFunction(func) { return func && Object.prototype.toString.call(func) === '[object Function]'; }; _proto.mainTimerEvent = function mainTimerEvent() { this._remainingSeconds--; if (this.isFunction(this.tick)) { if (this._remainingSeconds <= 0 && this._timeoutMode === CountDownTimeoutMode.loop) { this._remainingSeconds = this._timeoutSeconds; } //tick事件需在ontimeout之前触发 this.tick(this._remainingSeconds); } if (this._remainingSeconds <= 0) { if (this._timeoutMode === CountDownTimeoutMode.once) { this._timerStatus = CountDownTimerStatus.stop; this.stop(); } else if (this._timeoutMode === CountDownTimeoutMode.loop) { this.reset(); } //loop模式,每次也应该触发超时事件 if (this.isFunction(this.onTimeout)) { this.onTimeout(); } } }; _createClass(CountDownTimer, [{ key: "remainingSeconds", get: function get() { return this._remainingSeconds; } // set remainingSeconds(seconds) { // this._remainingSeconds = seconds; // } //超时时间 }, { key: "timeoutSeconds", get: function get() { return this._timeoutSeconds; }, set: function set(seconds) { this._timeoutSeconds = seconds; this._remainingSeconds = seconds; } //定时器状态 }, { key: "timerStatus", get: function get() { return this._timerStatus; } //超时模式 }, { key: "timeoutMode", get: function get() { return this._timeoutMode; }, set: function set(mode) { this._timeoutMode = mode; } }]); return CountDownTimer; }(); exports.CountDownTimeoutMode = CountDownTimeoutMode; exports.CountDownTimer = CountDownTimer; exports.CountDownTimerStatus = CountDownTimerStatus; exports.Timer = Timer; Object.defineProperty(exports, '__esModule', { value: true }); }));