@oscarpalmer/timer 0.40.0 → 0.41.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 CHANGED
@@ -1,4 +1,3 @@
1
- import FRAME_RATE_MS from "@oscarpalmer/atoms/frame-rate";
2
1
  /**
3
2
  * Buffer value to use when evaluating if a specific time is within a certain range
4
3
  */
@@ -28,4 +27,4 @@ const WORK_PAUSE = "pause";
28
27
  const WORK_RESTART = "restart";
29
28
  const WORK_START = "start";
30
29
  const WORK_STOP = "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 };
30
+ export { BUFFER_INTERVAL, DEFAULT_TIMEOUT, 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/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { delay } from "./delay.js";
2
1
  import "./global.js";
3
2
  import { isRepeated, isTimer, isWaited, isWhen } from "./is.js";
4
3
  import { repeat } from "./repeat.js";
5
4
  import { wait } from "./wait.js";
6
5
  import { when } from "./when.js";
6
+ import { delay } from "@oscarpalmer/atoms/promise";
7
7
  export { delay, isRepeated, isTimer, isWaited, isWhen, repeat, wait, when };
package/dist/is.js CHANGED
@@ -1,4 +1,4 @@
1
- import { TYPE_REPEAT, TYPE_WAIT, TYPE_WHEN } from "./constants.js";
1
+ import { TYPE_REPEAT, TYPE_WAIT } from "./constants.js";
2
2
  function is(names, value) {
3
3
  return names.includes(value?.$timer);
4
4
  }
package/dist/repeat.js CHANGED
@@ -1,4 +1,4 @@
1
- import { FRAME_RATE_MS, TYPE_REPEAT } from "./constants.js";
1
+ import { 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";
@@ -17,7 +17,7 @@ function repeat(callback, options) {
17
17
  onAfter: getCallback(options?.onAfter),
18
18
  onError: getCallback(options?.onTimeout),
19
19
  count: getValidNumber(options?.count),
20
- interval: getValidNumber(options?.interval, FRAME_RATE_MS),
20
+ interval: getValidNumber(options?.interval),
21
21
  timeout: getValidNumber(options?.timeout)
22
22
  }, true);
23
23
  }
@@ -1,24 +1,3 @@
1
- function calculate() {
2
- return new Promise((resolve) => {
3
- const values = [];
4
- let last;
5
- function step(now) {
6
- if (last != null) values.push(now - last);
7
- last = now;
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
- else requestAnimationFrame(step);
10
- }
11
- requestAnimationFrame(step);
12
- });
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;
22
1
  /**
23
2
  * Buffer value to use when evaluating if a specific time is within a certain range
24
3
  */
@@ -62,37 +41,75 @@ document.addEventListener("visibilitychange", () => {
62
41
  }
63
42
  from.clear();
64
43
  });
65
- function noop() {}
66
- new Set([
67
- Int8Array,
68
- Uint8Array,
69
- Uint8ClampedArray,
70
- Int16Array,
71
- Uint16Array,
72
- Int32Array,
73
- Uint32Array,
74
- Float32Array,
75
- Float64Array,
76
- BigInt64Array,
77
- BigUint64Array
78
- ]);
79
- function getCallback(value) {
80
- return typeof value === "function" ? value : noop;
44
+ const PROMISE_ABORT_OPTIONS = { once: true };
45
+ const PROMISE_EVENT_NAME = "abort";
46
+ function getNumberOrDefault(value) {
47
+ return typeof value === "number" && value > 0 ? value : 0;
81
48
  }
82
- function getValidTimeout(value) {
83
- return typeof value === "number" && value > 0 ? value : DEFAULT_TIMEOUT;
49
+ function getPromiseOptions(input) {
50
+ if (typeof input === "number") return { time: getNumberOrDefault(input) };
51
+ if (input instanceof AbortSignal) return {
52
+ signal: input,
53
+ time: 0
54
+ };
55
+ const options = typeof input === "object" && input !== null ? input : {};
56
+ return {
57
+ signal: options.signal instanceof AbortSignal ? options.signal : void 0,
58
+ time: getNumberOrDefault(options.time)
59
+ };
84
60
  }
85
- function getValidNumber(value, defaultValue) {
86
- const actualDefault = defaultValue ?? 0;
87
- return typeof value === "number" && value > actualDefault ? value : actualDefault;
61
+ function settlePromise(aborter, settler, value, signal) {
62
+ signal?.removeEventListener(PROMISE_EVENT_NAME, aborter);
63
+ settler(value);
88
64
  }
89
- /**
90
- * Create a delayed promise that resolves after a certain amount of time
91
- * @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
92
- * @returns A promise that resolves after the delay
93
- */
94
- function delay(time) {
95
- return new Promise((resolve) => setTimeout(resolve, getValidNumber(time)));
65
+ function getInterval(value) {
66
+ return typeof value === "number" && value > 0 ? value : 0;
67
+ }
68
+ function getTimer(type, callback, time) {
69
+ const interval = getInterval(time);
70
+ function run(now) {
71
+ start ??= now;
72
+ if (interval === 0 || now - start >= interval - OFFSET) {
73
+ if (throttle) start = now;
74
+ callback(...args);
75
+ } else frame = requestAnimationFrame(run);
76
+ }
77
+ const throttle = type === TIMER_THROTTLE;
78
+ let args;
79
+ let frame;
80
+ let start;
81
+ const timer = (...parameters) => {
82
+ timer.cancel();
83
+ args = parameters;
84
+ frame = requestAnimationFrame(run);
85
+ };
86
+ timer.cancel = () => {
87
+ cancelAnimationFrame(frame);
88
+ };
89
+ return timer;
90
+ }
91
+ var OFFSET = 5;
92
+ const TIMER_THROTTLE = "throttle";
93
+ const TIMER_WAIT = "wait";
94
+ function delay(options) {
95
+ const { signal, time } = getPromiseOptions(options);
96
+ if (signal?.aborted ?? false) return Promise.reject(signal.reason);
97
+ function abort() {
98
+ timer.cancel();
99
+ rejector(signal.reason);
100
+ }
101
+ const timer = getTimer(TIMER_WAIT, () => {
102
+ settlePromise(abort, resolver, void 0, signal);
103
+ }, time);
104
+ signal?.addEventListener("abort", abort, PROMISE_ABORT_OPTIONS);
105
+ let rejector;
106
+ let resolver;
107
+ return new Promise((resolve, reject) => {
108
+ rejector = reject;
109
+ resolver = resolve;
110
+ if (time === 0) settlePromise(abort, resolve, void 0, signal);
111
+ else timer();
112
+ });
96
113
  }
97
114
  function is(names, value) {
98
115
  return names.includes(value?.$timer);
@@ -129,6 +146,20 @@ function isWaited(value) {
129
146
  function isWhen(value) {
130
147
  return is([TYPE_WHEN], value) && typeof value.then === "function";
131
148
  }
149
+ /**
150
+ * A function that does nothing, which can be useful, I guess…
151
+ */
152
+ function noop() {}
153
+ function getCallback(value) {
154
+ return typeof value === "function" ? value : noop;
155
+ }
156
+ function getValidTimeout(value) {
157
+ return typeof value === "number" && value > 0 ? value : DEFAULT_TIMEOUT;
158
+ }
159
+ function getValidNumber(value, defaultValue) {
160
+ const actualDefault = defaultValue ?? 0;
161
+ return typeof value === "number" && value > actualDefault ? value : actualDefault;
162
+ }
132
163
  var TimerTrace = class extends Error {
133
164
  constructor() {
134
165
  super();
@@ -170,7 +201,7 @@ function run(timer, state, options) {
170
201
  finish(timer, state, options, false);
171
202
  return;
172
203
  }
173
- if (options.interval === frame_rate_default || state.elapsed >= options.interval - BUFFER_INTERVAL) {
204
+ if (options.interval === 0 || state.elapsed >= options.interval - BUFFER_INTERVAL) {
174
205
  if (options.count > -1) state.callback(state.index);
175
206
  start = now;
176
207
  state.elapsed = 0;
@@ -320,7 +351,7 @@ function repeat(callback, options) {
320
351
  onAfter: getCallback(options?.onAfter),
321
352
  onError: getCallback(options?.onTimeout),
322
353
  count: getValidNumber(options?.count),
323
- interval: getValidNumber(options?.interval, frame_rate_default),
354
+ interval: getValidNumber(options?.interval),
324
355
  timeout: getValidNumber(options?.timeout)
325
356
  }, true);
326
357
  }
@@ -337,7 +368,7 @@ function wait(callback, time) {
337
368
  onAfter: void 0,
338
369
  onError: void 0,
339
370
  count: -1,
340
- interval: getValidNumber(time, frame_rate_default),
371
+ interval: getValidNumber(time),
341
372
  timeout: 0
342
373
  }, true);
343
374
  }
@@ -404,7 +435,7 @@ var When = class {
404
435
  this.destroy();
405
436
  },
406
437
  count: getValidNumber(options?.count),
407
- interval: getValidNumber(options?.interval, frame_rate_default),
438
+ interval: getValidNumber(options?.interval),
408
439
  timeout: getValidTimeout(options?.timeout)
409
440
  }, false);
410
441
  }
package/dist/wait.js CHANGED
@@ -1,4 +1,4 @@
1
- import { FRAME_RATE_MS, TYPE_WAIT } from "./constants.js";
1
+ import { 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";
@@ -16,7 +16,7 @@ function wait(callback, time) {
16
16
  onAfter: void 0,
17
17
  onError: void 0,
18
18
  count: -1,
19
- interval: getValidNumber(time, FRAME_RATE_MS),
19
+ interval: getValidNumber(time),
20
20
  timeout: 0
21
21
  }, true);
22
22
  }
package/dist/when.js CHANGED
@@ -1,4 +1,4 @@
1
- import { FRAME_RATE_MS, MESSAGE_DESTROYED, MESSAGE_STARTED, TYPE_WHEN } from "./constants.js";
1
+ import { 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";
@@ -67,7 +67,7 @@ var When = class {
67
67
  this.destroy();
68
68
  },
69
69
  count: getValidNumber(options?.count),
70
- interval: getValidNumber(options?.interval, FRAME_RATE_MS),
70
+ interval: getValidNumber(options?.interval),
71
71
  timeout: getValidTimeout(options?.timeout)
72
72
  }, false);
73
73
  }
package/dist/work.js CHANGED
@@ -1,4 +1,4 @@
1
- import { BUFFER_INTERVAL, FRAME_RATE_MS, TIMERS_ACTIVE, TYPE_WAIT, WORK_CONTINUE, WORK_PAUSE, WORK_RESTART, WORK_START, WORK_STOP } from "./constants.js";
1
+ import { TIMERS_ACTIVE, WORK_PAUSE, 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 === FRAME_RATE_MS || state.elapsed >= options.interval - 5) {
37
+ if (options.interval === 0 || 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.117"
7
+ "@oscarpalmer/atoms": "^0.152"
8
8
  },
9
9
  "description": "A better solution for timeout- and interval-based timers.",
10
10
  "devDependencies": {
11
- "@types/node": "^25.2",
11
+ "@types/node": "^25.3",
12
12
  "@vitest/coverage-istanbul": "^4",
13
13
  "jsdom": "^28.1",
14
- "oxfmt": "^0.33",
15
- "oxlint": "^1.48",
16
- "rolldown": "1.0.0-rc.4",
14
+ "oxfmt": "^0.36",
15
+ "oxlint": "^1.51",
16
+ "rolldown": "1.0.0-rc.6",
17
17
  "tslib": "^2.8",
18
18
  "typescript": "^5.9",
19
- "vite": "8.0.0-beta.14",
19
+ "vite": "8.0.0-beta.16",
20
20
  "vitest": "^4"
21
21
  },
22
22
  "exports": {
@@ -70,5 +70,5 @@
70
70
  },
71
71
  "type": "module",
72
72
  "types": "types/index.d.ts",
73
- "version": "0.40.0"
73
+ "version": "0.41.0"
74
74
  }
package/src/constants.ts CHANGED
@@ -1,4 +1,3 @@
1
- import FRAME_RATE_MS from '@oscarpalmer/atoms/frame-rate';
2
1
  import type {TimerType, WorkHandlerType} from './models';
3
2
  import type {Timer} from './timer';
4
3
 
@@ -44,5 +43,3 @@ export const WORK_RESTART: WorkHandlerType = 'restart';
44
43
  export const WORK_START: WorkHandlerType = 'start';
45
44
 
46
45
  export const WORK_STOP: WorkHandlerType = 'stop';
47
-
48
- export {FRAME_RATE_MS};
package/src/index.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import './global';
2
2
 
3
- export * from './delay';
3
+ export {delay} from '@oscarpalmer/atoms/promise';
4
4
  export {isRepeated, isTimer, isWaited, isWhen} from './is';
5
5
  export * from './repeat';
6
6
  export type {Timer} from './timer';
package/src/repeat.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {FRAME_RATE_MS, TYPE_REPEAT} from './constants';
1
+ import {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, FRAME_RATE_MS),
24
+ interval: getValidNumber(options?.interval),
25
25
  timeout: getValidNumber(options?.timeout),
26
26
  },
27
27
  true,
package/src/wait.ts CHANGED
@@ -1,4 +1,4 @@
1
- import {FRAME_RATE_MS, TYPE_WAIT} from './constants';
1
+ import {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, FRAME_RATE_MS),
23
+ interval: getValidNumber(time),
24
24
  timeout: 0,
25
25
  },
26
26
  true,
package/src/when.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import {noop} from '@oscarpalmer/atoms/function';
2
- import {FRAME_RATE_MS, MESSAGE_DESTROYED, MESSAGE_STARTED, TYPE_WHEN} from './constants';
2
+ import {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';
@@ -90,7 +90,7 @@ class When {
90
90
  this.destroy();
91
91
  },
92
92
  count: getValidNumber(options?.count),
93
- interval: getValidNumber(options?.interval, FRAME_RATE_MS),
93
+ interval: getValidNumber(options?.interval),
94
94
  timeout: getValidTimeout(options?.timeout),
95
95
  },
96
96
  false,
package/src/work.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  import {
2
2
  TIMERS_ACTIVE,
3
3
  BUFFER_INTERVAL,
4
- FRAME_RATE_MS,
5
4
  TYPE_WAIT,
6
5
  WORK_CONTINUE,
7
6
  WORK_PAUSE,
@@ -84,7 +83,7 @@ function run(
84
83
  return;
85
84
  }
86
85
 
87
- if (options.interval === FRAME_RATE_MS || state.elapsed >= options.interval - BUFFER_INTERVAL) {
86
+ if (options.interval === 0 || state.elapsed >= options.interval - BUFFER_INTERVAL) {
88
87
  if (options.count > -1) {
89
88
  (state.callback as (index: number) => void)(state.index);
90
89
  }
@@ -1,4 +1,3 @@
1
- import FRAME_RATE_MS from '@oscarpalmer/atoms/frame-rate';
2
1
  import type { TimerType, WorkHandlerType } from './models';
3
2
  import type { Timer } from './timer';
4
3
  /**
@@ -30,4 +29,3 @@ export declare const WORK_PAUSE: WorkHandlerType;
30
29
  export declare const WORK_RESTART: WorkHandlerType;
31
30
  export declare const WORK_START: WorkHandlerType;
32
31
  export declare const WORK_STOP: WorkHandlerType;
33
- export { FRAME_RATE_MS };
package/types/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import './global';
2
- export * from './delay';
2
+ export { delay } from '@oscarpalmer/atoms/promise';
3
3
  export { isRepeated, isTimer, isWaited, isWhen } from './is';
4
4
  export * from './repeat';
5
5
  export type { Timer } from './timer';
package/dist/delay.js DELETED
@@ -1,10 +0,0 @@
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
- */
7
- function delay(time) {
8
- return new Promise((resolve) => setTimeout(resolve, getValidNumber(time)));
9
- }
10
- export { delay };
package/src/delay.ts DELETED
@@ -1,10 +0,0 @@
1
- import {getValidNumber} from './get';
2
-
3
- /**
4
- * Create a delayed promise that resolves after a certain amount of time
5
- * @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
6
- * @returns A promise that resolves after the delay
7
- */
8
- export function delay(time?: number): Promise<void> {
9
- return new Promise(resolve => setTimeout(resolve, getValidNumber(time)));
10
- }
package/types/delay.d.ts DELETED
@@ -1,6 +0,0 @@
1
- /**
2
- * Create a delayed promise that resolves after a certain amount of time
3
- * @param time How long to wait for _(in milliseconds; defaults to screen refresh rate)_
4
- * @returns A promise that resolves after the delay
5
- */
6
- export declare function delay(time?: number): Promise<void>;