@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
JavaScript
"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;