reactronic
Version:
Reactronic - Transactional Reactive State Management
147 lines (146 loc) • 6.29 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
import { Isolation } from "../Enums.js";
import { SxObject, Mvcc } from "./Mvcc.js";
import { Transaction } from "./Transaction.js";
export class Indicator extends SxObject {
static create(hint, activationDelay, deactivationDelay, durationResolution) {
return IndicatorImpl.createImpl(hint, activationDelay, deactivationDelay, durationResolution);
}
}
export class IndicatorImpl extends Indicator {
constructor() {
super(...arguments);
this.isBusy = false;
this.counter = 0;
this.workers = new Set();
this.busyDuration = 0;
this.internals = {
whenBusy: undefined,
resolveWhenBusy: undefined,
whenIdle: undefined,
resolveWhenIdle: undefined,
started: 0,
activationDelay: -1,
activationTimeout: undefined,
deactivationDelay: -1,
deactivationTimeout: undefined,
durationResolution: 1,
};
}
whenBusy() {
return __awaiter(this, void 0, void 0, function* () {
if (this.internals.started === 0) {
if (!this.internals.whenBusy) {
this.internals.whenBusy = new Promise((resolve, reject) => {
this.internals.resolveWhenBusy = resolve;
});
}
yield this.internals.whenBusy;
}
});
}
whenIdle() {
return __awaiter(this, void 0, void 0, function* () {
if (this.internals.started !== 0) {
if (!this.internals.whenIdle) {
this.internals.whenIdle = new Promise((resolve, reject) => {
this.internals.resolveWhenIdle = resolve;
});
}
yield this.internals.whenIdle;
}
});
}
enter(worker) {
this.counter++;
const workers = this.workers = this.workers.toMutable();
workers.add(worker);
IndicatorImpl.activate(this, this.internals.activationDelay);
}
leave(worker) {
this.counter--;
const workers = this.workers = this.workers.toMutable();
workers.delete(worker);
IndicatorImpl.deactivate(this, this.internals.deactivationDelay);
}
static createImpl(hint, activationDelay, deactivationDelay, durationResolution) {
return Transaction.run({ hint: "Indicator.create" }, IndicatorImpl.doCreate, hint, activationDelay, deactivationDelay, durationResolution);
}
static enter(mon, worker) {
mon.enter(worker);
}
static leave(mon, worker) {
mon.leave(worker);
}
static doCreate(hint, activationDelay, deactivationDelay, durationResolution) {
const ind = new IndicatorImpl();
Mvcc.setHint(ind, hint);
ind.internals.activationDelay = activationDelay;
ind.internals.deactivationDelay = deactivationDelay;
ind.internals.durationResolution = durationResolution;
return ind;
}
static activate(mon, delay) {
const active = mon.counter > 0;
if (mon.internals.started === 0 && active) {
mon.busyDuration = 0;
mon.internals.started = performance.now();
if (mon.internals.whenBusy) {
const resolve = mon.internals.resolveWhenBusy;
mon.internals.whenBusy = undefined;
mon.internals.resolveWhenBusy = undefined;
resolve();
}
IndicatorImpl.tick(mon);
}
if (delay >= 0) {
if (mon.internals.activationTimeout === undefined)
mon.internals.activationTimeout = setTimeout(() => Transaction.run({ hint: "Indicator.activate", isolation: Isolation.disjoinFromOuterAndInnerTransactions }, IndicatorImpl.activate, mon, -1), delay);
}
else if (active)
mon.isBusy = true;
}
static deactivate(mon, delay) {
if (delay >= 0) {
clearTimeout(mon.internals.deactivationTimeout);
mon.internals.deactivationTimeout = setTimeout(() => Transaction.run({ hint: "Indicator.deactivate", isolation: Isolation.disjoinFromOuterAndInnerTransactions }, IndicatorImpl.deactivate, mon, -1), delay);
}
else if (mon.counter <= 0) {
mon.isBusy = false;
mon.internals.activationTimeout = undefined;
}
if (mon.counter === 0 && mon.internals.started !== 0) {
const resolution = mon.internals.durationResolution;
mon.busyDuration = Math.round(resolution * (performance.now() - mon.internals.started)) / resolution;
mon.internals.started = 0;
if (mon.internals.whenIdle) {
const resolve = mon.internals.resolveWhenIdle;
mon.internals.whenIdle = undefined;
mon.internals.resolveWhenIdle = undefined;
resolve();
}
}
}
static tick(mon) {
if (mon.internals.started !== 0) {
const resolution = mon.internals.durationResolution;
mon.busyDuration = Math.round(resolution * (performance.now() - mon.internals.started)) / resolution;
const t = globalThis !== null && globalThis !== void 0 ? globalThis : global;
if (t.requestAnimationFrame)
requestAnimationFrame(() => {
Transaction.run(INDICATOR_TICK_OPTIONS, () => IndicatorImpl.tick(mon));
});
}
}
}
const INDICATOR_TICK_OPTIONS = Object.freeze({
hint: "Indicator.tick",
});