UNPKG

@webkrafters/long-count

Version:

Long Count - intervals and timeout capable of handling superbly long wait times surviving device sleep and wake cycles.

426 lines (425 loc) 18.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _constants = require("../constants"); var _$global = require("../$global"); var _index = require("../util/index"); var _index2 = require("../util/int-xl/index"); var _index3 = require("./helpers/index"); var _invoke = _interopRequireDefault(require("./helpers/decorators/invoke")); var _index4 = _interopRequireDefault(require("../observable/index")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _toConsumableArray(r) { return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray(r) || _nonIterableSpread(); } function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } } function _iterableToArray(r) { if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) return Array.from(r); } function _arrayWithoutHoles(r) { if (Array.isArray(r)) return _arrayLikeToArray(r); } function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; } function _classCallCheck(a, n) { if (!(a instanceof n)) throw new TypeError("Cannot call a class as a function"); } function _defineProperties(e, r) { for (var t = 0; t < r.length; t++) { var o = r[t]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(e, _toPropertyKey(o.key), o); } } function _createClass(e, r, t) { return r && _defineProperties(e.prototype, r), t && _defineProperties(e, t), Object.defineProperty(e, "prototype", { writable: !1 }), e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); } function _possibleConstructorReturn(t, e) { if (e && ("object" == _typeof(e) || "function" == typeof e)) return e; if (void 0 !== e) throw new TypeError("Derived constructors may only return object or undefined"); return _assertThisInitialized(t); } function _assertThisInitialized(e) { if (void 0 === e) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return e; } function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); } function _getPrototypeOf(t) { return _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function (t) { return t.__proto__ || Object.getPrototypeOf(t); }, _getPrototypeOf(t); } function _inherits(t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function"); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, writable: !0, configurable: !0 } }), Object.defineProperty(t, "prototype", { writable: !1 }), e && _setPrototypeOf(t, e); } function _setPrototypeOf(t, e) { return _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function (t, e) { return t.__proto__ = e, t; }, _setPrototypeOf(t, e); } function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var __runInitializers = void 0 && (void 0).__runInitializers || function (thisArg, initializers, value) { var useValue = arguments.length > 2; for (var i = 0; i < initializers.length; i++) { value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg); } return useValue ? value : void 0; }; var __esDecorate = void 0 && (void 0).__esDecorate || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) { function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; } var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value"; var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null; var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {}); var _, done = false; for (var i = decorators.length - 1; i >= 0; i--) { var context = {}; for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p]; for (var p in contextIn.access) context.access[p] = contextIn.access[p]; context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); }; var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context); if (kind === "accessor") { if (result === void 0) continue; if (result === null || _typeof(result) !== "object") throw new TypeError("Object expected"); if (_ = accept(result.get)) descriptor.get = _; if (_ = accept(result.set)) descriptor.set = _; if (_ = accept(result.init)) initializers.unshift(_); } else if (_ = accept(result)) { if (kind === "field") initializers.unshift(_);else descriptor[key] = _; } } if (target) Object.defineProperty(target, contextIn.name, descriptor); done = true; }; var Timer = function () { var _a; var _classSuper = _index4["default"]; var _instanceExtraInitializers = []; var _beginIteration_decorators; var _execute_decorators; var _notifyCycleEnd_decorators; var _notifyResume_decorators; var _onContinuityChange_decorators; var _resume_decorators; var _suspend_decorators; return _a = /*#__PURE__*/function (_classSuper2) { function Timer(fn) { var _options$maxTimeoutDe; var _this; var delay = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : _constants.EMPTY_OBJECT; _classCallCheck(this, Timer); _this = _callSuper(this, Timer); _this._continuityWatch = __runInitializers(_this, _instanceExtraInitializers); _this._disposed = false; _this._numCycles = 0; // global settimeout invocations currently made in the life of this timer. _this._handler = fn; _this._maxIterDuration = (_options$maxTimeoutDe = options.maxTimeoutDelay) !== null && _options$maxTimeoutDe !== void 0 ? _options$maxTimeoutDe : _constants.MAX_SET_TIMEOUT_DELAY; // istanbul ignore next for (var _len = arguments.length, args = new Array(_len > 3 ? _len - 3 : 0), _key = 3; _key < _len; _key++) { args[_key - 3] = arguments[_key]; } _this._payload = args || _constants.EMPTY_ARRAY; _this._totalUntouchedDelay = (0, _index3.sanitizeDelay)(delay); _this.persist(); _this.beginIteration(); options.immediate && _this.execute(); return _this; } _inherits(Timer, _classSuper2); return _createClass(Timer, [{ key: "continuityWatch", get: function get() { return this._continuityWatch; } // time spent in current iteration // istanbul ignore next }, { key: "currentIterElaspedTime", get: function get() { return !this._cycleStart ? 0 : Date.now() - this._cycleStart; } }, { key: "currentWaitTime", get: function get() { if (!this._cycleStart) { return 0; } var iterRemaining = this._currentIterDuration - this.currentIterElaspedTime; return this._totalUntouchedDelay ? (0, _index2.add)(iterRemaining, this._totalUntouchedDelay) : iterRemaining; } }, { key: "disposed", get: function get() { return this._disposed; } }, { key: "beginIteration", value: function beginIteration() { switch ((0, _index.getTypeOf)(this._totalUntouchedDelay)) { case 'Number': { var delay = this._totalUntouchedDelay; if (delay <= this._maxIterDuration) { this._currentIterDuration = delay; this._totalUntouchedDelay = undefined; break; } this._currentIterDuration = this._maxIterDuration; this._totalUntouchedDelay = delay - this._maxIterDuration; break; } case 'Uint8Array': { this._totalUntouchedDelay = (0, _index2.subtract)(this._totalUntouchedDelay, this._maxIterDuration); this._currentIterDuration = this._maxIterDuration; break; } // istanbul ignore next default: return this.exit(); } this.setTimeout(); } }, { key: "clearTimeout", value: function clearTimeout() { if (typeof this._timeoutId === 'undefined') { return; } _$global.$global.clearTimeout(this._timeoutId); this._timeoutId = undefined; } }, { key: "endIteration", value: function endIteration() { this.clearTimeout(); if (!this._totalUntouchedDelay) { this.execute(); this.notifyCycleEnd(true); return this.exit(); } this.notifyCycleEnd(); this.beginIteration(); } }, { key: "execute", value: function execute() { this._handler.apply(this, _toConsumableArray(this._payload)); } }, { key: "exit", value: function exit() { this.clearTimeout(); this._continuityWatch && _$global.$global.document.removeEventListener('visibilitychange', this._continuityWatch); this.dispatchEvent('exit', { timeRemaining: this.currentWaitTime }); this._continuityWatch = this._cycleStart = this._handler = this._payload = this._totalUntouchedDelay = undefined; this._currentIterDuration = 0; for (var k in this._observers) { this._observers[k].clear(); } this._disposed = true; } }, { key: "notifyCycleEnd", value: function notifyCycleEnd() { var isFinal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; this.dispatchEvent('cycleEnding', { currentCycle: this._numCycles, isFinal: isFinal, time: Date.now() }); } }, { key: "notifyResume", value: function notifyResume() { this.dispatchEvent('resume', { timeRemaining: this.currentWaitTime }); } }, { key: "onContinuityChange", value: function onContinuityChange() { switch (_$global.$global.document.visibilityState) { case 'hidden': return this.suspend(); case 'visible': return this.resume(); } } }, { key: "persist", value: function persist() { var _this2 = this; if (_$global.$global.document.addEventListener === _index.noop) { return _$global.$global.console.warn('Cannot conduct long count with this machine. The Global document property with `addEventListener` method not supported.'); } this._continuityWatch = function () { return _this2.onContinuityChange(); }; _$global.$global.document.addEventListener('visibilitychange', this._continuityWatch); } }, { key: "resume", value: function resume() { var sleepDuration = Date.now() - this._suspendedAt; var preSleepIterRemaining = this._currentIterDuration - (this._suspendedAt - this._cycleStart); var postIterSleepLength = sleepDuration - preSleepIterRemaining; /* did not completely sleep through the iteration */ if (postIterSleepLength <= 0) { this._currentIterDuration = Math.abs(postIterSleepLength); this.notifyResume(); return this.setTimeout(); } /* slept through the entire timer delay */ if (!this._totalUntouchedDelay || (0, _index2.isGreaterThan)(postIterSleepLength, this._totalUntouchedDelay)) { this._cycleStart = undefined; this.notifyResume(); this.execute(); return this.exit(); } /* slept through at least the current iteration but not the entire timer delay */ this._totalUntouchedDelay = (0, _index2.subtract)(this._totalUntouchedDelay, Date.now() - this._cycleStart); this.notifyResume(); this.beginIteration(); } }, { key: "setTimeout", value: function setTimeout() { var _this3 = this; // istanbul ignore next this._timeoutId && console.info('overriding current active timer'); this._timeoutId = _$global.$global.setTimeout(function () { return _this3.endIteration(); }, this._currentIterDuration - 10 // 10 ms error margin to account for record keeping and other call preparation ); var isInit = !this._cycleStart; this._cycleStart = Date.now(); this.dispatchEvent('cycleStarted', { currentCycle: ++this._numCycles, isInit: isInit, time: this._cycleStart }); } }, { key: "suspend", value: function suspend() { // istanbul ignore next if (!this._cycleStart) { return; } this._suspendedAt = Date.now(); this.clearTimeout(); this.dispatchEvent('suspend', { timeRemaining: this.currentWaitTime }); } }]); }(_classSuper), function (_classSuper$Symbol$me) { var _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create((_classSuper$Symbol$me = _classSuper[Symbol.metadata]) !== null && _classSuper$Symbol$me !== void 0 ? _classSuper$Symbol$me : null) : void 0; _beginIteration_decorators = [_invoke["default"]]; _execute_decorators = [_invoke["default"]]; _notifyCycleEnd_decorators = [_invoke["default"]]; _notifyResume_decorators = [_invoke["default"]]; _onContinuityChange_decorators = [_invoke["default"]]; _resume_decorators = [_invoke["default"]]; _suspend_decorators = [_invoke["default"]]; __esDecorate(_a, null, _beginIteration_decorators, { kind: "method", name: "beginIteration", "static": false, "private": false, access: { has: function has(obj) { return "beginIteration" in obj; }, get: function get(obj) { return obj.beginIteration; } }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(_a, null, _execute_decorators, { kind: "method", name: "execute", "static": false, "private": false, access: { has: function has(obj) { return "execute" in obj; }, get: function get(obj) { return obj.execute; } }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(_a, null, _notifyCycleEnd_decorators, { kind: "method", name: "notifyCycleEnd", "static": false, "private": false, access: { has: function has(obj) { return "notifyCycleEnd" in obj; }, get: function get(obj) { return obj.notifyCycleEnd; } }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(_a, null, _notifyResume_decorators, { kind: "method", name: "notifyResume", "static": false, "private": false, access: { has: function has(obj) { return "notifyResume" in obj; }, get: function get(obj) { return obj.notifyResume; } }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(_a, null, _onContinuityChange_decorators, { kind: "method", name: "onContinuityChange", "static": false, "private": false, access: { has: function has(obj) { return "onContinuityChange" in obj; }, get: function get(obj) { return obj.onContinuityChange; } }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(_a, null, _resume_decorators, { kind: "method", name: "resume", "static": false, "private": false, access: { has: function has(obj) { return "resume" in obj; }, get: function get(obj) { return obj.resume; } }, metadata: _metadata }, null, _instanceExtraInitializers); __esDecorate(_a, null, _suspend_decorators, { kind: "method", name: "suspend", "static": false, "private": false, access: { has: function has(obj) { return "suspend" in obj; }, get: function get(obj) { return obj.suspend; } }, metadata: _metadata }, null, _instanceExtraInitializers); if (_metadata) Object.defineProperty(_a, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata }); }(), _a; }(); var _default = exports["default"] = Timer;