-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathClock.js
136 lines (122 loc) · 5.72 KB
/
Clock.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import {WebSystemObject} from "./WebSystemObject.js";
export class Clock extends WebSystemObject {
// Nota técnica: Utiliza un único manipulador, para mapear el tiempo de procesos vitales, industriales o sensibles que deben ser exactos, deberías utilizar otros métodos,
// como rutinas a bajo nivel precompiladas por lenguajes de alto nivel.
static _intervalLatency = 15; // increases to 100ms to improve cpu use if not enough the cap of 50ms to ensure responsiveness within the threshold of human perception.
static _intervalHandler = -1; // take the unique 50ms interval handler and share others ()
static _intervalData = [];
constructor(duration = 1000, oninterval = null, active = true) {
super();
this.id = this.autoField(Clock._intervalData, 'id');
Clock.stopService();
Clock._intervalData.push(this.newInterval(oninterval, duration, active, 0, this.id));
Clock._intervalData.sort((a, b) => a.duration - b.duration); // prioritary duration
if (Clock._intervalData.length > 0) {
// Just bcoz we're sampling a time process, have to follow the Nyquist-Kotelnikov theorem.
Clock._intervalLatency = Math.max(15, (Math.round(Clock._intervalData[0].duration / 2))); // 5 ms is the min tolerance.
}
this.active = active; // now we can use active, instead startService...
}
// esta activa o desactiva.
get active() {
return Clock._intervalData[this.id].active;
}
set active(state) {
Clock.stopService();
Clock._intervalData[this.id].active = state;
Clock._intervalData[this.id].baseTime = Number(new Date());
Clock._intervalData[this.id].latchCounter = Clock._intervalData[this.id].baseTime;
Clock._intervalData[this.id].reachTime = Clock._intervalData[this.id].baseTime + Clock._intervalData[this.id].duration - Clock._intervalLatency;
if (state) Clock.startService();
}
// este es el evento
get oninterval() {
return Clock._intervalData[this.oninterval];
}
// Eventos para el temporizador
set oninterval(oninterval) {
Clock.stopService();
Clock._intervalData[this.id].oninterval = oninterval;
Clock.startService();
}
static _intervalEvent = async () => { // ti mer
Clock._intervalData.forEach((interval) => {
let now;
let attention = true;
let delay;
while (attention && interval.active) {
attention = false;
interval.latchCounter += Clock._intervalLatency; // oh no, is time elapsed
now = now ? now : Number(new Date());
delay = now - interval.reachTime + (interval.QoS_MeanDelay / 2);
if (delay >= 0) {
// Demora media en la calidad del servicio, en milisegundos: (calidad = QoS_MeanDelay/duration, 0 -> Tiempo real, < 0.5 Eficiente, > 0.5 Ineficiente, 1 Imposible, (serve for Shannon theorem in transm.)
interval.QoS_MeanDelay = (interval.QoS_MeanDelay * interval.occurrences + delay) / (interval.occurrences + 1);
interval.occurrences++;
interval.baseTime = now;
interval.reachTime = interval.reachTime + interval.duration; // for next time
if (interval.oninterval) {
attention = true;
new Promise(async function (resolve, reject) {
try {
resolve(interval.oninterval(interval.occurrences)); // i promise you that...
} catch (error) {
reject(error);
}
});
}
}
}
});
};
static enableIntervalTimer = () => {
Clock._intervalHandler = setInterval(Clock._intervalEvent, Clock._intervalLatency);
};
static disableIntervalTimer = () => {
clearInterval(Clock._intervalHandler);
};
newInterval(oninterval, duration = 1000, active = true, occurrences = 0, id = 0) {
const baseTime = Number(new Date());
return {
'id': id,
'oninterval': oninterval,
'latchCounter': baseTime,
'duration': duration,
'baseTime': baseTime,
'reachTime': baseTime + duration,
'active': active,
'occurrences': 0,
'QoS_MeanDelay': 0,
};
}
// Para evitar alterar algún elemento de _intervalData mientras esté siendo utilizado por _intervalEvent //
static stopService() {
if (Clock._intervalHandler !== -1) {
Clock.disableIntervalTimer();
}
}
static startService() {
Clock.enableIntervalTimer();
}
// Esta reinicia el contador...
resetLatchCounter() {
Clock.stopService();
const position = Clock._intervalData.findIndex((element) => element.id === this.id);
if (position !== -1) {
Clock._intervalData[position].baseTime = Number(new Date());
Clock._intervalData[position].latchCounter = Clock._intervalData[position].baseTime;
Clock._intervalData[position].reachTime = Clock._intervalData[position].baseTime + Clock._intervalData[position].duration - Clock._intervalLatency;
Clock.startService();
}
}
// Usa esta para liberar el cronómetro, antes de destruir el objeto...
free() {
Clock.stopService();
Clock._intervalData = Clock._intervalData.filter((element) => element.id !== this.id);
// Y el último apaga
if (Clock._intervalData.length > 0) {
Clock.startService();
}
// super.free();
}
}