@oscarpalmer/timer 0.38.1 → 0.40.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.js +17 -18
- package/dist/delay.js +6 -11
- package/dist/is.js +20 -0
- package/dist/repeat.js +8 -2
- package/dist/timer.full.js +19 -59
- package/dist/timer.js +31 -1
- package/dist/wait.js +7 -2
- package/dist/when.js +46 -3
- package/dist/work.js +2 -2
- package/package.json +9 -9
- package/src/constants.ts +2 -43
- package/src/delay.ts +1 -18
- package/src/repeat.ts +2 -2
- package/src/timer.ts +3 -1
- package/src/wait.ts +2 -2
- package/src/when.ts +7 -3
- package/src/work.ts +2 -2
- package/types/constants.d.ts +2 -4
package/dist/constants.js
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function step(now) {
|
|
6
|
-
if (last != null) values.push(now - last);
|
|
7
|
-
last = now;
|
|
8
|
-
if (values.length >= 10) resolve(values.sort().slice(2, -2).reduce((first, second) => first + second, 0) / (values.length - 4));
|
|
9
|
-
else requestAnimationFrame(step);
|
|
10
|
-
}
|
|
11
|
-
requestAnimationFrame(step);
|
|
12
|
-
});
|
|
13
|
-
}
|
|
1
|
+
import FRAME_RATE_MS from "@oscarpalmer/atoms/frame-rate";
|
|
2
|
+
/**
|
|
3
|
+
* Buffer value to use when evaluating if a specific time is within a certain range
|
|
4
|
+
*/
|
|
14
5
|
const BUFFER_INTERVAL = 5;
|
|
15
6
|
const DEFAULT_TIMEOUT = 3e4;
|
|
7
|
+
/**
|
|
8
|
+
* Message to show when a when-timer is destroyed
|
|
9
|
+
*/
|
|
16
10
|
const MESSAGE_DESTROYED = "Timer has already been destroyed";
|
|
11
|
+
/**
|
|
12
|
+
* Message to show when a when-timer is started
|
|
13
|
+
*/
|
|
17
14
|
const MESSAGE_STARTED = "Timer has already been started";
|
|
15
|
+
/**
|
|
16
|
+
* A set of all active timers
|
|
17
|
+
*/
|
|
18
18
|
const TIMERS_ACTIVE = /* @__PURE__ */ new Set();
|
|
19
|
+
/**
|
|
20
|
+
* A set of timers that were paused due to the document being hidden
|
|
21
|
+
*/
|
|
19
22
|
const TIMERS_HIDDEN = /* @__PURE__ */ new Set();
|
|
20
23
|
const TYPE_REPEAT = "repeat";
|
|
21
24
|
const TYPE_WAIT = "wait";
|
|
@@ -25,8 +28,4 @@ const WORK_PAUSE = "pause";
|
|
|
25
28
|
const WORK_RESTART = "restart";
|
|
26
29
|
const WORK_START = "start";
|
|
27
30
|
const WORK_STOP = "stop";
|
|
28
|
-
|
|
29
|
-
calculate().then((value) => {
|
|
30
|
-
MILLISECONDS = value;
|
|
31
|
-
});
|
|
32
|
-
export { BUFFER_INTERVAL, DEFAULT_TIMEOUT, MESSAGE_DESTROYED, MESSAGE_STARTED, MILLISECONDS, TIMERS_ACTIVE, TIMERS_HIDDEN, TYPE_REPEAT, TYPE_WAIT, TYPE_WHEN, WORK_CONTINUE, WORK_PAUSE, WORK_RESTART, WORK_START, WORK_STOP };
|
|
31
|
+
export { BUFFER_INTERVAL, DEFAULT_TIMEOUT, FRAME_RATE_MS, MESSAGE_DESTROYED, MESSAGE_STARTED, TIMERS_ACTIVE, TIMERS_HIDDEN, TYPE_REPEAT, TYPE_WAIT, TYPE_WHEN, WORK_CONTINUE, WORK_PAUSE, WORK_RESTART, WORK_START, WORK_STOP };
|
package/dist/delay.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import { BUFFER_INTERVAL, MILLISECONDS } from "./constants.js";
|
|
2
1
|
import { getValidNumber } from "./get.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create a delayed promise that resolves after a certain amount of time
|
|
4
|
+
* @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
|
|
5
|
+
* @returns A promise that resolves after the delay
|
|
6
|
+
*/
|
|
3
7
|
function delay(time) {
|
|
4
|
-
return new Promise((resolve) =>
|
|
5
|
-
const interval = getValidNumber(time, MILLISECONDS);
|
|
6
|
-
let start;
|
|
7
|
-
function step(now) {
|
|
8
|
-
start ??= now;
|
|
9
|
-
if (interval === MILLISECONDS || now - start >= interval - 5) resolve();
|
|
10
|
-
else requestAnimationFrame(step);
|
|
11
|
-
}
|
|
12
|
-
requestAnimationFrame(step);
|
|
13
|
-
});
|
|
8
|
+
return new Promise((resolve) => setTimeout(resolve, getValidNumber(time)));
|
|
14
9
|
}
|
|
15
10
|
export { delay };
|
package/dist/is.js
CHANGED
|
@@ -2,15 +2,35 @@ import { TYPE_REPEAT, TYPE_WAIT, TYPE_WHEN } from "./constants.js";
|
|
|
2
2
|
function is(names, value) {
|
|
3
3
|
return names.includes(value?.$timer);
|
|
4
4
|
}
|
|
5
|
+
/**
|
|
6
|
+
* Is the value a repeating timer?
|
|
7
|
+
* @param value Value to check
|
|
8
|
+
* @returns `true` if the value is a repeating timer
|
|
9
|
+
*/
|
|
5
10
|
function isRepeated(value) {
|
|
6
11
|
return is([TYPE_REPEAT], value);
|
|
7
12
|
}
|
|
13
|
+
/**
|
|
14
|
+
* Is the value a timer?
|
|
15
|
+
* @param value Value to check
|
|
16
|
+
* @returns `true` if the value is a timer
|
|
17
|
+
*/
|
|
8
18
|
function isTimer(value) {
|
|
9
19
|
return is([TYPE_REPEAT, TYPE_WAIT], value);
|
|
10
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Is the value a waiting timer?
|
|
23
|
+
* @param value Value to check
|
|
24
|
+
* @returns `true` if the value is a waiting timer
|
|
25
|
+
*/
|
|
11
26
|
function isWaited(value) {
|
|
12
27
|
return is([TYPE_WAIT], value);
|
|
13
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Is the value a conditional timer?
|
|
31
|
+
* @param value Value to check
|
|
32
|
+
* @returns `true` if the value is a conditional timer
|
|
33
|
+
*/
|
|
14
34
|
function isWhen(value) {
|
|
15
35
|
return is(["when"], value) && typeof value.then === "function";
|
|
16
36
|
}
|
package/dist/repeat.js
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FRAME_RATE_MS, TYPE_REPEAT } from "./constants.js";
|
|
2
2
|
import { getCallback, getValidNumber } from "./get.js";
|
|
3
3
|
import "./global.js";
|
|
4
4
|
import { TimerTrace } from "./models.js";
|
|
5
5
|
import { Timer } from "./timer.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create a repeating timer
|
|
8
|
+
* @param callback Callback to run on each interval
|
|
9
|
+
* @param options Timer options
|
|
10
|
+
* @returns Timer instance
|
|
11
|
+
*/
|
|
6
12
|
function repeat(callback, options) {
|
|
7
13
|
return new Timer(TYPE_REPEAT, {
|
|
8
14
|
callback: getCallback(callback),
|
|
@@ -11,7 +17,7 @@ function repeat(callback, options) {
|
|
|
11
17
|
onAfter: getCallback(options?.onAfter),
|
|
12
18
|
onError: getCallback(options?.onTimeout),
|
|
13
19
|
count: getValidNumber(options?.count),
|
|
14
|
-
interval: getValidNumber(options?.interval,
|
|
20
|
+
interval: getValidNumber(options?.interval, FRAME_RATE_MS),
|
|
15
21
|
timeout: getValidNumber(options?.timeout)
|
|
16
22
|
}, true);
|
|
17
23
|
}
|
package/dist/timer.full.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
|
-
function calculate
|
|
1
|
+
function calculate() {
|
|
2
2
|
return new Promise((resolve) => {
|
|
3
3
|
const values = [];
|
|
4
4
|
let last;
|
|
5
5
|
function step(now) {
|
|
6
6
|
if (last != null) values.push(now - last);
|
|
7
7
|
last = now;
|
|
8
|
-
if (values.length >=
|
|
8
|
+
if (values.length >= CALCULATION_TOTAL) resolve(values.sort().slice(CALCULATION_TRIM_PART, -CALCULATION_TRIM_PART).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM_TOTAL));
|
|
9
9
|
else requestAnimationFrame(step);
|
|
10
10
|
}
|
|
11
11
|
requestAnimationFrame(step);
|
|
12
12
|
});
|
|
13
13
|
}
|
|
14
|
+
var CALCULATION_TOTAL = 10;
|
|
15
|
+
var CALCULATION_TRIM_PART = 2;
|
|
16
|
+
var CALCULATION_TRIM_TOTAL = 4;
|
|
17
|
+
var FRAME_RATE_MS = 1e3 / 60;
|
|
18
|
+
calculate().then((value) => {
|
|
19
|
+
FRAME_RATE_MS = value;
|
|
20
|
+
});
|
|
21
|
+
var frame_rate_default = FRAME_RATE_MS;
|
|
14
22
|
/**
|
|
15
23
|
* Buffer value to use when evaluating if a specific time is within a certain range
|
|
16
24
|
*/
|
|
@@ -40,14 +48,6 @@ const WORK_PAUSE = "pause";
|
|
|
40
48
|
const WORK_RESTART = "restart";
|
|
41
49
|
const WORK_START = "start";
|
|
42
50
|
const WORK_STOP = "stop";
|
|
43
|
-
/**
|
|
44
|
-
* A calculated average of the refresh rate of the display _(in milliseconds)_
|
|
45
|
-
*/
|
|
46
|
-
let MILLISECONDS = 1e3 / 60;
|
|
47
|
-
calculate$1().then((value) => {
|
|
48
|
-
MILLISECONDS = value;
|
|
49
|
-
});
|
|
50
|
-
|
|
51
51
|
if (globalThis._oscarpalmer_timers == null) Object.defineProperty(globalThis, "_oscarpalmer_timers", { get() {
|
|
52
52
|
return globalThis._oscarpalmer_timer_debug ? [...TIMERS_ACTIVE] : [];
|
|
53
53
|
} });
|
|
@@ -62,29 +62,8 @@ document.addEventListener("visibilitychange", () => {
|
|
|
62
62
|
}
|
|
63
63
|
from.clear();
|
|
64
64
|
});
|
|
65
|
-
|
|
66
|
-
function calculate() {
|
|
67
|
-
return new Promise((resolve) => {
|
|
68
|
-
const values = [];
|
|
69
|
-
let last;
|
|
70
|
-
function step(now) {
|
|
71
|
-
if (last != null) values.push(now - last);
|
|
72
|
-
last = now;
|
|
73
|
-
if (values.length >= CALCULATION_TOTAL) resolve(values.sort().slice(2, -2).reduce((first, second) => first + second, 0) / (values.length - CALCULATION_TRIM));
|
|
74
|
-
else requestAnimationFrame(step);
|
|
75
|
-
}
|
|
76
|
-
requestAnimationFrame(step);
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
65
|
function noop() {}
|
|
80
|
-
|
|
81
|
-
var CALCULATION_TRIM = 4;
|
|
82
|
-
let milliseconds = 1e3 / 60;
|
|
83
|
-
calculate().then((value) => {
|
|
84
|
-
milliseconds = value;
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
var TYPED_ARRAYS = new Set([
|
|
66
|
+
new Set([
|
|
88
67
|
Int8Array,
|
|
89
68
|
Uint8Array,
|
|
90
69
|
Uint8ClampedArray,
|
|
@@ -97,7 +76,6 @@ var TYPED_ARRAYS = new Set([
|
|
|
97
76
|
BigInt64Array,
|
|
98
77
|
BigUint64Array
|
|
99
78
|
]);
|
|
100
|
-
|
|
101
79
|
function getCallback(value) {
|
|
102
80
|
return typeof value === "function" ? value : noop;
|
|
103
81
|
}
|
|
@@ -108,25 +86,14 @@ function getValidNumber(value, defaultValue) {
|
|
|
108
86
|
const actualDefault = defaultValue ?? 0;
|
|
109
87
|
return typeof value === "number" && value > actualDefault ? value : actualDefault;
|
|
110
88
|
}
|
|
111
|
-
|
|
112
89
|
/**
|
|
113
90
|
* Create a delayed promise that resolves after a certain amount of time
|
|
114
91
|
* @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
|
|
115
92
|
* @returns A promise that resolves after the delay
|
|
116
93
|
*/
|
|
117
94
|
function delay(time) {
|
|
118
|
-
return new Promise((resolve) =>
|
|
119
|
-
const interval = getValidNumber(time, MILLISECONDS);
|
|
120
|
-
let start;
|
|
121
|
-
function step(now) {
|
|
122
|
-
start ??= now;
|
|
123
|
-
if (interval === MILLISECONDS || now - start >= interval - BUFFER_INTERVAL) resolve();
|
|
124
|
-
else requestAnimationFrame(step);
|
|
125
|
-
}
|
|
126
|
-
requestAnimationFrame(step);
|
|
127
|
-
});
|
|
95
|
+
return new Promise((resolve) => setTimeout(resolve, getValidNumber(time)));
|
|
128
96
|
}
|
|
129
|
-
|
|
130
97
|
function is(names, value) {
|
|
131
98
|
return names.includes(value?.$timer);
|
|
132
99
|
}
|
|
@@ -162,14 +129,12 @@ function isWaited(value) {
|
|
|
162
129
|
function isWhen(value) {
|
|
163
130
|
return is([TYPE_WHEN], value) && typeof value.then === "function";
|
|
164
131
|
}
|
|
165
|
-
|
|
166
132
|
var TimerTrace = class extends Error {
|
|
167
133
|
constructor() {
|
|
168
134
|
super();
|
|
169
135
|
this.name = "TimerTrace";
|
|
170
136
|
}
|
|
171
137
|
};
|
|
172
|
-
|
|
173
138
|
function finish(timer, state, options, success) {
|
|
174
139
|
cancelAnimationFrame(state.frame);
|
|
175
140
|
TIMERS_ACTIVE.delete(timer.instance);
|
|
@@ -205,7 +170,7 @@ function run(timer, state, options) {
|
|
|
205
170
|
finish(timer, state, options, false);
|
|
206
171
|
return;
|
|
207
172
|
}
|
|
208
|
-
if (options.interval ===
|
|
173
|
+
if (options.interval === frame_rate_default || state.elapsed >= options.interval - BUFFER_INTERVAL) {
|
|
209
174
|
if (options.count > -1) state.callback(state.index);
|
|
210
175
|
start = now;
|
|
211
176
|
state.elapsed = 0;
|
|
@@ -249,7 +214,6 @@ function work(type, timer, state, options) {
|
|
|
249
214
|
state.frame = requestAnimationFrame(runner);
|
|
250
215
|
return timer.instance;
|
|
251
216
|
}
|
|
252
|
-
|
|
253
217
|
var Timer = class {
|
|
254
218
|
state;
|
|
255
219
|
/**
|
|
@@ -278,7 +242,7 @@ var Timer = class {
|
|
|
278
242
|
}
|
|
279
243
|
constructor(type, state, options, start) {
|
|
280
244
|
this.options = options;
|
|
281
|
-
this
|
|
245
|
+
Object.defineProperty(this, "$timer", { value: type });
|
|
282
246
|
this.state = {
|
|
283
247
|
...state,
|
|
284
248
|
active: false,
|
|
@@ -342,7 +306,6 @@ var Timer = class {
|
|
|
342
306
|
}, this.state, this.options);
|
|
343
307
|
}
|
|
344
308
|
};
|
|
345
|
-
|
|
346
309
|
/**
|
|
347
310
|
* Create a repeating timer
|
|
348
311
|
* @param callback Callback to run on each interval
|
|
@@ -357,11 +320,10 @@ function repeat(callback, options) {
|
|
|
357
320
|
onAfter: getCallback(options?.onAfter),
|
|
358
321
|
onError: getCallback(options?.onTimeout),
|
|
359
322
|
count: getValidNumber(options?.count),
|
|
360
|
-
interval: getValidNumber(options?.interval,
|
|
323
|
+
interval: getValidNumber(options?.interval, frame_rate_default),
|
|
361
324
|
timeout: getValidNumber(options?.timeout)
|
|
362
325
|
}, true);
|
|
363
326
|
}
|
|
364
|
-
|
|
365
327
|
/**
|
|
366
328
|
* Create a waiting timer
|
|
367
329
|
* @param callback Callback to run when the timer has finished
|
|
@@ -375,13 +337,11 @@ function wait(callback, time) {
|
|
|
375
337
|
onAfter: void 0,
|
|
376
338
|
onError: void 0,
|
|
377
339
|
count: -1,
|
|
378
|
-
interval: getValidNumber(time,
|
|
340
|
+
interval: getValidNumber(time, frame_rate_default),
|
|
379
341
|
timeout: 0
|
|
380
342
|
}, true);
|
|
381
343
|
}
|
|
382
|
-
|
|
383
344
|
var When = class {
|
|
384
|
-
$timer = TYPE_WHEN;
|
|
385
345
|
state = {
|
|
386
346
|
promise: void 0,
|
|
387
347
|
rejecter: void 0,
|
|
@@ -414,6 +374,7 @@ var When = class {
|
|
|
414
374
|
return globalThis._oscarpalmer_timer_debug ?? false ? this.state.timer?.trace : void 0;
|
|
415
375
|
}
|
|
416
376
|
constructor(condition, options) {
|
|
377
|
+
Object.defineProperty(this, "$timer", { value: TYPE_WHEN });
|
|
417
378
|
const { state } = this;
|
|
418
379
|
state.promise = new Promise((resolve, reject) => {
|
|
419
380
|
state.resolver = resolve;
|
|
@@ -443,7 +404,7 @@ var When = class {
|
|
|
443
404
|
this.destroy();
|
|
444
405
|
},
|
|
445
406
|
count: getValidNumber(options?.count),
|
|
446
|
-
interval: getValidNumber(options?.interval,
|
|
407
|
+
interval: getValidNumber(options?.interval, frame_rate_default),
|
|
447
408
|
timeout: getValidTimeout(options?.timeout)
|
|
448
409
|
}, false);
|
|
449
410
|
}
|
|
@@ -513,5 +474,4 @@ var When = class {
|
|
|
513
474
|
function when(condition, options) {
|
|
514
475
|
return new When(condition, options);
|
|
515
476
|
}
|
|
516
|
-
|
|
517
|
-
export { delay, isRepeated, isTimer, isWaited, isWhen, repeat, wait, when };
|
|
477
|
+
export { delay, isRepeated, isTimer, isWaited, isWhen, repeat, wait, when };
|
package/dist/timer.js
CHANGED
|
@@ -3,21 +3,33 @@ import { stop, work } from "./work.js";
|
|
|
3
3
|
import { noop } from "@oscarpalmer/atoms/function";
|
|
4
4
|
var Timer = class {
|
|
5
5
|
state;
|
|
6
|
+
/**
|
|
7
|
+
* Is the timer active?
|
|
8
|
+
*/
|
|
6
9
|
get active() {
|
|
7
10
|
return this.state.active;
|
|
8
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Is the timer destroyed?
|
|
14
|
+
*/
|
|
9
15
|
get destroyed() {
|
|
10
16
|
return this.state.destroyed;
|
|
11
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* Is the timer paused?
|
|
20
|
+
*/
|
|
12
21
|
get paused() {
|
|
13
22
|
return this.state.paused;
|
|
14
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Get the timer's origin _(if debugging is enabled)_
|
|
26
|
+
*/
|
|
15
27
|
get trace() {
|
|
16
28
|
return globalThis._oscarpalmer_timer_debug ?? false ? this.state.trace : void 0;
|
|
17
29
|
}
|
|
18
30
|
constructor(type, state, options, start) {
|
|
19
31
|
this.options = options;
|
|
20
|
-
this
|
|
32
|
+
Object.defineProperty(this, "$timer", { value: type });
|
|
21
33
|
this.state = {
|
|
22
34
|
...state,
|
|
23
35
|
active: false,
|
|
@@ -30,9 +42,15 @@ var Timer = class {
|
|
|
30
42
|
};
|
|
31
43
|
if (start) this.start();
|
|
32
44
|
}
|
|
45
|
+
/**
|
|
46
|
+
* Continue running the timer _(if it's paused)_
|
|
47
|
+
*/
|
|
33
48
|
continue() {
|
|
34
49
|
return this.#work(WORK_CONTINUE);
|
|
35
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* Destroy the timer
|
|
53
|
+
*/
|
|
36
54
|
destroy() {
|
|
37
55
|
this.state.destroyed = true;
|
|
38
56
|
this.options.onAfter = noop;
|
|
@@ -44,15 +62,27 @@ var Timer = class {
|
|
|
44
62
|
type: this.$timer
|
|
45
63
|
}, this.state, this.options);
|
|
46
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* Pause the timer _(if it's running)_
|
|
67
|
+
*/
|
|
47
68
|
pause() {
|
|
48
69
|
return this.#work(WORK_PAUSE);
|
|
49
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Restart the timer _(or start it, if it's not running)_
|
|
73
|
+
*/
|
|
50
74
|
restart() {
|
|
51
75
|
return this.#work(WORK_RESTART);
|
|
52
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* Start the timer _(if it's not running)_
|
|
79
|
+
*/
|
|
53
80
|
start() {
|
|
54
81
|
return this.#work(WORK_START);
|
|
55
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Stop the timer _(if it's running)_
|
|
85
|
+
*/
|
|
56
86
|
stop() {
|
|
57
87
|
return this.#work(WORK_STOP);
|
|
58
88
|
}
|
package/dist/wait.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FRAME_RATE_MS, TYPE_WAIT } from "./constants.js";
|
|
2
2
|
import { getCallback, getValidNumber } from "./get.js";
|
|
3
3
|
import "./global.js";
|
|
4
4
|
import { TimerTrace } from "./models.js";
|
|
5
5
|
import { Timer } from "./timer.js";
|
|
6
|
+
/**
|
|
7
|
+
* Create a waiting timer
|
|
8
|
+
* @param callback Callback to run when the timer has finished
|
|
9
|
+
* @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
|
|
10
|
+
*/
|
|
6
11
|
function wait(callback, time) {
|
|
7
12
|
return new Timer(TYPE_WAIT, {
|
|
8
13
|
callback: getCallback(callback),
|
|
@@ -11,7 +16,7 @@ function wait(callback, time) {
|
|
|
11
16
|
onAfter: void 0,
|
|
12
17
|
onError: void 0,
|
|
13
18
|
count: -1,
|
|
14
|
-
interval: getValidNumber(time,
|
|
19
|
+
interval: getValidNumber(time, FRAME_RATE_MS),
|
|
15
20
|
timeout: 0
|
|
16
21
|
}, true);
|
|
17
22
|
}
|
package/dist/when.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import { MESSAGE_DESTROYED, MESSAGE_STARTED,
|
|
1
|
+
import { FRAME_RATE_MS, MESSAGE_DESTROYED, MESSAGE_STARTED, TYPE_WHEN } from "./constants.js";
|
|
2
2
|
import { getValidNumber, getValidTimeout } from "./get.js";
|
|
3
3
|
import "./global.js";
|
|
4
4
|
import { TimerTrace } from "./models.js";
|
|
5
5
|
import { Timer } from "./timer.js";
|
|
6
6
|
import { noop } from "@oscarpalmer/atoms/function";
|
|
7
7
|
var When = class {
|
|
8
|
-
$timer = TYPE_WHEN;
|
|
9
8
|
state = {
|
|
10
9
|
promise: void 0,
|
|
11
10
|
rejecter: void 0,
|
|
@@ -13,19 +12,32 @@ var When = class {
|
|
|
13
12
|
started: false,
|
|
14
13
|
timer: void 0
|
|
15
14
|
};
|
|
15
|
+
/**
|
|
16
|
+
* Is the timer active?
|
|
17
|
+
*/
|
|
16
18
|
get active() {
|
|
17
19
|
return this.state.timer?.active ?? false;
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Is the timer destroyed?
|
|
23
|
+
*/
|
|
19
24
|
get destroyed() {
|
|
20
25
|
return this.state.timer == null;
|
|
21
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Is the timer paused?
|
|
29
|
+
*/
|
|
22
30
|
get paused() {
|
|
23
31
|
return this.state.timer?.paused ?? false;
|
|
24
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Get the timer's origin _(if debugging is enabled)_
|
|
35
|
+
*/
|
|
25
36
|
get trace() {
|
|
26
37
|
return globalThis._oscarpalmer_timer_debug ?? false ? this.state.timer?.trace : void 0;
|
|
27
38
|
}
|
|
28
39
|
constructor(condition, options) {
|
|
40
|
+
Object.defineProperty(this, "$timer", { value: TYPE_WHEN });
|
|
29
41
|
const { state } = this;
|
|
30
42
|
state.promise = new Promise((resolve, reject) => {
|
|
31
43
|
state.resolver = resolve;
|
|
@@ -55,14 +67,20 @@ var When = class {
|
|
|
55
67
|
this.destroy();
|
|
56
68
|
},
|
|
57
69
|
count: getValidNumber(options?.count),
|
|
58
|
-
interval: getValidNumber(options?.interval,
|
|
70
|
+
interval: getValidNumber(options?.interval, FRAME_RATE_MS),
|
|
59
71
|
timeout: getValidTimeout(options?.timeout)
|
|
60
72
|
}, false);
|
|
61
73
|
}
|
|
74
|
+
/**
|
|
75
|
+
* Continues the timer _(if it was paused)_
|
|
76
|
+
*/
|
|
62
77
|
continue() {
|
|
63
78
|
this.state.timer?.continue();
|
|
64
79
|
return this;
|
|
65
80
|
}
|
|
81
|
+
/**
|
|
82
|
+
* Destroys the timer _(and stops it,if it was running)_
|
|
83
|
+
*/
|
|
66
84
|
destroy() {
|
|
67
85
|
const { state } = this;
|
|
68
86
|
state.timer?.destroy();
|
|
@@ -71,10 +89,19 @@ var When = class {
|
|
|
71
89
|
state.rejecter = noop;
|
|
72
90
|
state.timer = void 0;
|
|
73
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Pauses the timer _(if it was running)_
|
|
94
|
+
*/
|
|
74
95
|
pause() {
|
|
75
96
|
this.state.timer?.pause();
|
|
76
97
|
return this;
|
|
77
98
|
}
|
|
99
|
+
/**
|
|
100
|
+
* Start the timer
|
|
101
|
+
* @param resolve Optional resolve callback
|
|
102
|
+
* @param reject Optional reject callback
|
|
103
|
+
* @returns Promise that resolves when the condition is met
|
|
104
|
+
*/
|
|
78
105
|
start(resolve, reject) {
|
|
79
106
|
const { state } = this;
|
|
80
107
|
if (state.timer == null) throw new Error(MESSAGE_DESTROYED);
|
|
@@ -83,14 +110,30 @@ var When = class {
|
|
|
83
110
|
state.timer.start();
|
|
84
111
|
return state.promise.then(resolve ?? noop, reject ?? noop);
|
|
85
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Stops the timer _(if it was running)_
|
|
115
|
+
*/
|
|
86
116
|
stop() {
|
|
87
117
|
this.state.timer?.stop();
|
|
88
118
|
return this;
|
|
89
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* Start the timer
|
|
122
|
+
* @deprecated Use `start()` instead
|
|
123
|
+
* @param resolve Optional resolve callback
|
|
124
|
+
* @param reject Optional reject callback
|
|
125
|
+
* @returns Promise that resolves when the condition is met
|
|
126
|
+
*/
|
|
90
127
|
then(resolve, reject) {
|
|
91
128
|
return this.start(resolve, reject);
|
|
92
129
|
}
|
|
93
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* Create a conditional timer
|
|
133
|
+
* @param condition Condition to check
|
|
134
|
+
* @param options Timer options
|
|
135
|
+
* @returns Timer instance
|
|
136
|
+
*/
|
|
94
137
|
function when(condition, options) {
|
|
95
138
|
return new When(condition, options);
|
|
96
139
|
}
|
package/dist/work.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BUFFER_INTERVAL,
|
|
1
|
+
import { BUFFER_INTERVAL, FRAME_RATE_MS, TIMERS_ACTIVE, TYPE_WAIT, WORK_CONTINUE, WORK_PAUSE, WORK_RESTART, WORK_START, WORK_STOP } from "./constants.js";
|
|
2
2
|
function finish(timer, state, options, success) {
|
|
3
3
|
cancelAnimationFrame(state.frame);
|
|
4
4
|
TIMERS_ACTIVE.delete(timer.instance);
|
|
@@ -34,7 +34,7 @@ function run(timer, state, options) {
|
|
|
34
34
|
finish(timer, state, options, false);
|
|
35
35
|
return;
|
|
36
36
|
}
|
|
37
|
-
if (options.interval ===
|
|
37
|
+
if (options.interval === FRAME_RATE_MS || state.elapsed >= options.interval - 5) {
|
|
38
38
|
if (options.count > -1) state.callback(state.index);
|
|
39
39
|
start = now;
|
|
40
40
|
state.elapsed = 0;
|
package/package.json
CHANGED
|
@@ -4,19 +4,19 @@
|
|
|
4
4
|
"url": "https://oscarpalmer.se"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
|
-
"@oscarpalmer/atoms": "^0.
|
|
7
|
+
"@oscarpalmer/atoms": "^0.117"
|
|
8
8
|
},
|
|
9
9
|
"description": "A better solution for timeout- and interval-based timers.",
|
|
10
10
|
"devDependencies": {
|
|
11
|
-
"@types/node": "^25",
|
|
11
|
+
"@types/node": "^25.2",
|
|
12
12
|
"@vitest/coverage-istanbul": "^4",
|
|
13
|
-
"jsdom": "^
|
|
14
|
-
"oxfmt": "^0.
|
|
15
|
-
"oxlint": "^1.
|
|
16
|
-
"rolldown": "1.0.0-
|
|
13
|
+
"jsdom": "^28.1",
|
|
14
|
+
"oxfmt": "^0.33",
|
|
15
|
+
"oxlint": "^1.48",
|
|
16
|
+
"rolldown": "1.0.0-rc.4",
|
|
17
17
|
"tslib": "^2.8",
|
|
18
18
|
"typescript": "^5.9",
|
|
19
|
-
"vite": "8.0.0-beta.
|
|
19
|
+
"vite": "8.0.0-beta.14",
|
|
20
20
|
"vitest": "^4"
|
|
21
21
|
},
|
|
22
22
|
"exports": {
|
|
@@ -64,11 +64,11 @@
|
|
|
64
64
|
"build": "npm run clean && npx vite build && npm run rolldown:build && npx tsc",
|
|
65
65
|
"clean": "rm -rf ./dist && rm -rf ./types && rm -f ./tsconfig.tsbuildinfo",
|
|
66
66
|
"rolldown:build": "npx rolldown -c",
|
|
67
|
-
"rolldown:watch": "npx rolldown -c --watch",
|
|
67
|
+
"rolldown:watch": "npx rolldown -c ./rolldown.config.js --watch",
|
|
68
68
|
"test": "npx vitest --coverage",
|
|
69
69
|
"watch": "npx vite build --watch"
|
|
70
70
|
},
|
|
71
71
|
"type": "module",
|
|
72
72
|
"types": "types/index.d.ts",
|
|
73
|
-
"version": "0.
|
|
73
|
+
"version": "0.40.0"
|
|
74
74
|
}
|
package/src/constants.ts
CHANGED
|
@@ -1,39 +1,7 @@
|
|
|
1
|
+
import FRAME_RATE_MS from '@oscarpalmer/atoms/frame-rate';
|
|
1
2
|
import type {TimerType, WorkHandlerType} from './models';
|
|
2
3
|
import type {Timer} from './timer';
|
|
3
4
|
|
|
4
|
-
function calculate(): Promise<number> {
|
|
5
|
-
return new Promise(resolve => {
|
|
6
|
-
const values: number[] = [];
|
|
7
|
-
|
|
8
|
-
let last: DOMHighResTimeStamp | undefined;
|
|
9
|
-
|
|
10
|
-
function step(now: DOMHighResTimeStamp): void {
|
|
11
|
-
if (last != null) {
|
|
12
|
-
values.push(now - last);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
last = now;
|
|
16
|
-
|
|
17
|
-
if (values.length >= 10) {
|
|
18
|
-
const median =
|
|
19
|
-
values
|
|
20
|
-
.sort()
|
|
21
|
-
.slice(2, -2)
|
|
22
|
-
.reduce((first, second) => first + second, 0) /
|
|
23
|
-
(values.length - 4);
|
|
24
|
-
|
|
25
|
-
resolve(median);
|
|
26
|
-
} else {
|
|
27
|
-
requestAnimationFrame(step);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
requestAnimationFrame(step);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
//
|
|
36
|
-
|
|
37
5
|
/**
|
|
38
6
|
* Buffer value to use when evaluating if a specific time is within a certain range
|
|
39
7
|
*/
|
|
@@ -77,13 +45,4 @@ export const WORK_START: WorkHandlerType = 'start';
|
|
|
77
45
|
|
|
78
46
|
export const WORK_STOP: WorkHandlerType = 'stop';
|
|
79
47
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* A calculated average of the refresh rate of the display _(in milliseconds)_
|
|
84
|
-
*/
|
|
85
|
-
export let MILLISECONDS = 1000 / 60;
|
|
86
|
-
|
|
87
|
-
calculate().then(value => {
|
|
88
|
-
MILLISECONDS = value;
|
|
89
|
-
});
|
|
48
|
+
export {FRAME_RATE_MS};
|
package/src/delay.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {BUFFER_INTERVAL, MILLISECONDS} from './constants';
|
|
2
1
|
import {getValidNumber} from './get';
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -7,21 +6,5 @@ import {getValidNumber} from './get';
|
|
|
7
6
|
* @returns A promise that resolves after the delay
|
|
8
7
|
*/
|
|
9
8
|
export function delay(time?: number): Promise<void> {
|
|
10
|
-
return new Promise(resolve =>
|
|
11
|
-
const interval = getValidNumber(time, MILLISECONDS);
|
|
12
|
-
|
|
13
|
-
let start: DOMHighResTimeStamp;
|
|
14
|
-
|
|
15
|
-
function step(now: DOMHighResTimeStamp) {
|
|
16
|
-
start ??= now;
|
|
17
|
-
|
|
18
|
-
if (interval === MILLISECONDS || now - start >= interval - BUFFER_INTERVAL) {
|
|
19
|
-
resolve();
|
|
20
|
-
} else {
|
|
21
|
-
requestAnimationFrame(step);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
requestAnimationFrame(step);
|
|
26
|
-
});
|
|
9
|
+
return new Promise(resolve => setTimeout(resolve, getValidNumber(time)));
|
|
27
10
|
}
|
package/src/repeat.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {FRAME_RATE_MS, TYPE_REPEAT} from './constants';
|
|
2
2
|
import {getCallback, getValidNumber} from './get';
|
|
3
3
|
import './global';
|
|
4
4
|
import {type RepeatOptions, TimerTrace} from './models';
|
|
@@ -21,7 +21,7 @@ export function repeat(callback: (index: number) => void, options?: Partial<Repe
|
|
|
21
21
|
onAfter: getCallback(options?.onAfter),
|
|
22
22
|
onError: getCallback(options?.onTimeout),
|
|
23
23
|
count: getValidNumber(options?.count),
|
|
24
|
-
interval: getValidNumber(options?.interval,
|
|
24
|
+
interval: getValidNumber(options?.interval, FRAME_RATE_MS),
|
|
25
25
|
timeout: getValidNumber(options?.timeout),
|
|
26
26
|
},
|
|
27
27
|
true,
|
package/src/timer.ts
CHANGED
package/src/wait.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {FRAME_RATE_MS, TYPE_WAIT} from './constants';
|
|
2
2
|
import {getCallback, getValidNumber} from './get';
|
|
3
3
|
import './global';
|
|
4
4
|
import {TimerTrace} from './models';
|
|
@@ -20,7 +20,7 @@ export function wait(callback: () => void, time?: number): Timer {
|
|
|
20
20
|
onAfter: undefined,
|
|
21
21
|
onError: undefined,
|
|
22
22
|
count: -1,
|
|
23
|
-
interval: getValidNumber(time,
|
|
23
|
+
interval: getValidNumber(time, FRAME_RATE_MS),
|
|
24
24
|
timeout: 0,
|
|
25
25
|
},
|
|
26
26
|
true,
|
package/src/when.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import {noop} from '@oscarpalmer/atoms/function';
|
|
2
|
-
import {
|
|
2
|
+
import {FRAME_RATE_MS, MESSAGE_DESTROYED, MESSAGE_STARTED, TYPE_WHEN} from './constants';
|
|
3
3
|
import {getValidNumber, getValidTimeout} from './get';
|
|
4
4
|
import './global';
|
|
5
5
|
import {TimerTrace, type WhenOptions, type WhenState} from './models';
|
|
6
6
|
import {Timer} from './timer';
|
|
7
7
|
|
|
8
8
|
class When {
|
|
9
|
-
private readonly $timer
|
|
9
|
+
declare private readonly $timer: string;
|
|
10
10
|
|
|
11
11
|
private readonly state: WhenState = {
|
|
12
12
|
promise: undefined as never,
|
|
@@ -45,6 +45,10 @@ class When {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
constructor(condition: () => boolean, options?: Partial<WhenOptions>) {
|
|
48
|
+
Object.defineProperty(this, '$timer', {
|
|
49
|
+
value: TYPE_WHEN,
|
|
50
|
+
});
|
|
51
|
+
|
|
48
52
|
const {state} = this;
|
|
49
53
|
|
|
50
54
|
state.promise = new Promise<void>((resolve, reject) => {
|
|
@@ -86,7 +90,7 @@ class When {
|
|
|
86
90
|
this.destroy();
|
|
87
91
|
},
|
|
88
92
|
count: getValidNumber(options?.count),
|
|
89
|
-
interval: getValidNumber(options?.interval,
|
|
93
|
+
interval: getValidNumber(options?.interval, FRAME_RATE_MS),
|
|
90
94
|
timeout: getValidTimeout(options?.timeout),
|
|
91
95
|
},
|
|
92
96
|
false,
|
package/src/work.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TIMERS_ACTIVE,
|
|
3
3
|
BUFFER_INTERVAL,
|
|
4
|
-
|
|
4
|
+
FRAME_RATE_MS,
|
|
5
5
|
TYPE_WAIT,
|
|
6
6
|
WORK_CONTINUE,
|
|
7
7
|
WORK_PAUSE,
|
|
@@ -84,7 +84,7 @@ function run(
|
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
-
if (options.interval ===
|
|
87
|
+
if (options.interval === FRAME_RATE_MS || state.elapsed >= options.interval - BUFFER_INTERVAL) {
|
|
88
88
|
if (options.count > -1) {
|
|
89
89
|
(state.callback as (index: number) => void)(state.index);
|
|
90
90
|
}
|
package/types/constants.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import FRAME_RATE_MS from '@oscarpalmer/atoms/frame-rate';
|
|
1
2
|
import type { TimerType, WorkHandlerType } from './models';
|
|
2
3
|
import type { Timer } from './timer';
|
|
3
4
|
/**
|
|
@@ -29,7 +30,4 @@ export declare const WORK_PAUSE: WorkHandlerType;
|
|
|
29
30
|
export declare const WORK_RESTART: WorkHandlerType;
|
|
30
31
|
export declare const WORK_START: WorkHandlerType;
|
|
31
32
|
export declare const WORK_STOP: WorkHandlerType;
|
|
32
|
-
|
|
33
|
-
* A calculated average of the refresh rate of the display _(in milliseconds)_
|
|
34
|
-
*/
|
|
35
|
-
export declare let MILLISECONDS: number;
|
|
33
|
+
export { FRAME_RATE_MS };
|