@oscarpalmer/atoms 0.169.0 → 0.171.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.
@@ -1,23 +1,3 @@
1
- import { CancelableCallback, GenericCallback } from "../models.mjs";
2
1
  import { noop } from "../internal/function/misc.mjs";
3
2
  import { Memoized, MemoizedOptions, memoize } from "./memoize.mjs";
4
-
5
- //#region src/function/index.d.ts
6
- /**
7
- * Debounce a function, ensuring it is only called after `time` milliseconds have passed
8
- *
9
- * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
10
- * @param callback Callback to debounce
11
- * @param time Time in milliseconds to wait before calling the callback _(defaults to match frame rate)_
12
- * @returns Debounced callback with a `cancel` method
13
- */
14
- declare function debounce<Callback extends GenericCallback>(callback: Callback, time?: number): CancelableCallback<Callback>;
15
- /**
16
- * Throttle a function, ensuring it is only called once every `time` milliseconds
17
- * @param callback Callback to throttle
18
- * @param time Time in milliseconds to wait before calling the callback again _(defaults to match frame rate)_
19
- * @returns Throttled callback with a `cancel` method
20
- */
21
- declare function throttle<Callback extends GenericCallback>(callback: Callback, time?: number): CancelableCallback<Callback>;
22
- //#endregion
23
- export { type Memoized, type MemoizedOptions, debounce, memoize, noop, throttle };
3
+ export { type Memoized, type MemoizedOptions, memoize, noop };
@@ -1,26 +1,3 @@
1
1
  import { noop } from "../internal/function/misc.mjs";
2
- import { TIMER_DEBOUNCE, TIMER_THROTTLE, getTimer } from "../internal/function/timer.mjs";
3
2
  import { memoize } from "./memoize.mjs";
4
- //#region src/function/index.ts
5
- /**
6
- * Debounce a function, ensuring it is only called after `time` milliseconds have passed
7
- *
8
- * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
9
- * @param callback Callback to debounce
10
- * @param time Time in milliseconds to wait before calling the callback _(defaults to match frame rate)_
11
- * @returns Debounced callback with a `cancel` method
12
- */
13
- function debounce(callback, time) {
14
- return getTimer(TIMER_DEBOUNCE, callback, time);
15
- }
16
- /**
17
- * Throttle a function, ensuring it is only called once every `time` milliseconds
18
- * @param callback Callback to throttle
19
- * @param time Time in milliseconds to wait before calling the callback again _(defaults to match frame rate)_
20
- * @returns Throttled callback with a `cancel` method
21
- */
22
- function throttle(callback, time) {
23
- return getTimer(TIMER_THROTTLE, callback, time);
24
- }
25
- //#endregion
26
- export { debounce, memoize, noop, throttle };
3
+ export { memoize, noop };
@@ -0,0 +1,49 @@
1
+ import { AsyncCancelableCallback, CancelableCallback, GenericAsyncCallback, GenericCallback } from "../models.mjs";
2
+
3
+ //#region src/function/limit.d.ts
4
+ /**
5
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
6
+ *
7
+ * When called, successful _(finished)_ results will resolve and errors will reject.
8
+ *
9
+ * On subsequent calls, existing calls will be canceled _(rejected)_, the timer reset, and will wait another `time` milliseconds before the new call is made _(and so on...)_
10
+ * @param callback Callback to debounce
11
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
12
+ * @returns Debounced callback handler with a `cancel` method
13
+ */
14
+ declare function asyncDebounce<Callback extends GenericAsyncCallback | GenericCallback>(callback: Callback, time?: number): AsyncCancelableCallback<Callback>;
15
+ /**
16
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
17
+ *
18
+ * When called, successful _(finished)_ results will resolve and errors will reject.
19
+ *
20
+ * On subsequent calls, existing calls will be canceled _(rejected)_ and will wait until the next valid time to call the callback again _(and so on...)_
21
+ * @param callback Callback to throttle
22
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
23
+ * @returns Throttled callback handler with a `cancel` method
24
+ */
25
+ declare function asyncThrottle<Callback extends GenericAsyncCallback | GenericCallback>(callback: Callback, time?: number): AsyncCancelableCallback<Callback>;
26
+ /**
27
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
28
+ *
29
+ * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
30
+ * @param callback Callback to debounce
31
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
32
+ * @returns Debounced callback handler with a `cancel` method
33
+ */
34
+ declare function debounce<Callback extends GenericCallback>(callback: Callback, time?: number): CancelableCallback<Callback>;
35
+ declare namespace debounce {
36
+ var async: typeof asyncDebounce;
37
+ }
38
+ /**
39
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
40
+ * @param callback Callback to throttle
41
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
42
+ * @returns Throttled callback handler with a `cancel` method
43
+ */
44
+ declare function throttle<Callback extends GenericCallback>(callback: Callback, time?: number): CancelableCallback<Callback>;
45
+ declare namespace throttle {
46
+ var async: typeof asyncThrottle;
47
+ }
48
+ //#endregion
49
+ export { debounce, throttle };
@@ -0,0 +1,52 @@
1
+ import { TIMER_DEBOUNCE, TIMER_THROTTLE, getAsyncTimer, getTimer } from "../internal/function/timer.mjs";
2
+ //#region src/function/limit.ts
3
+ /**
4
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
5
+ *
6
+ * When called, successful _(finished)_ results will resolve and errors will reject.
7
+ *
8
+ * On subsequent calls, existing calls will be canceled _(rejected)_, the timer reset, and will wait another `time` milliseconds before the new call is made _(and so on...)_
9
+ * @param callback Callback to debounce
10
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
11
+ * @returns Debounced callback handler with a `cancel` method
12
+ */
13
+ function asyncDebounce(callback, time) {
14
+ return getAsyncTimer(TIMER_DEBOUNCE, callback, time);
15
+ }
16
+ /**
17
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
18
+ *
19
+ * When called, successful _(finished)_ results will resolve and errors will reject.
20
+ *
21
+ * On subsequent calls, existing calls will be canceled _(rejected)_ and will wait until the next valid time to call the callback again _(and so on...)_
22
+ * @param callback Callback to throttle
23
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
24
+ * @returns Throttled callback handler with a `cancel` method
25
+ */
26
+ function asyncThrottle(callback, time) {
27
+ return getAsyncTimer(TIMER_THROTTLE, callback, time);
28
+ }
29
+ /**
30
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
31
+ *
32
+ * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
33
+ * @param callback Callback to debounce
34
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
35
+ * @returns Debounced callback handler with a `cancel` method
36
+ */
37
+ function debounce(callback, time) {
38
+ return getTimer(TIMER_DEBOUNCE, callback, time);
39
+ }
40
+ debounce.async = asyncDebounce;
41
+ /**
42
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
43
+ * @param callback Callback to throttle
44
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
45
+ * @returns Throttled callback handler with a `cancel` method
46
+ */
47
+ function throttle(callback, time) {
48
+ return getTimer(TIMER_THROTTLE, callback, time);
49
+ }
50
+ throttle.async = asyncThrottle;
51
+ //#endregion
52
+ export { debounce, throttle };
package/dist/index.d.mts CHANGED
@@ -3,6 +3,15 @@
3
3
  * A generic array or object
4
4
  */
5
5
  type ArrayOrPlainObject = unknown[] | Record<PropertyKey, unknown>;
6
+ /**
7
+ * An asynchronous callback that can be canceled
8
+ */
9
+ type AsyncCancelableCallback<Callback extends GenericAsyncCallback | GenericCallback> = (ReturnType<Callback> extends Promise<any> ? (...args: Parameters<Callback>) => Promise<Awaited<ReturnType<Callback>>> : (...args: Parameters<Callback>) => Promise<ReturnType<Callback>>) & {
10
+ /**
11
+ * Cancel the callback
12
+ */
13
+ cancel: () => void;
14
+ };
6
15
  /**
7
16
  * For mathicng any `void`, `Date`, primitive, or `RegExp` values
8
17
  *
@@ -10,7 +19,7 @@ type ArrayOrPlainObject = unknown[] | Record<PropertyKey, unknown>;
10
19
  */
11
20
  type BuiltIns = void | Date | Primitive | RegExp;
12
21
  /**
13
- * An extend callback that can be canceled
22
+ * A synchronous callback that can be canceled
14
23
  */
15
24
  type CancelableCallback<Callback extends GenericCallback> = Callback & {
16
25
  /**
@@ -1636,23 +1645,51 @@ type Options = {
1636
1645
  */
1637
1646
  declare function memoize<Callback extends GenericCallback>(callback: Callback, options?: MemoizedOptions<Callback>): Memoized<Callback>;
1638
1647
  //#endregion
1639
- //#region src/function/index.d.ts
1648
+ //#region src/function/limit.d.ts
1649
+ /**
1650
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
1651
+ *
1652
+ * When called, successful _(finished)_ results will resolve and errors will reject.
1653
+ *
1654
+ * On subsequent calls, existing calls will be canceled _(rejected)_, the timer reset, and will wait another `time` milliseconds before the new call is made _(and so on...)_
1655
+ * @param callback Callback to debounce
1656
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1657
+ * @returns Debounced callback handler with a `cancel` method
1658
+ */
1659
+ declare function asyncDebounce<Callback extends GenericAsyncCallback | GenericCallback>(callback: Callback, time?: number): AsyncCancelableCallback<Callback>;
1660
+ /**
1661
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
1662
+ *
1663
+ * When called, successful _(finished)_ results will resolve and errors will reject.
1664
+ *
1665
+ * On subsequent calls, existing calls will be canceled _(rejected)_ and will wait until the next valid time to call the callback again _(and so on...)_
1666
+ * @param callback Callback to throttle
1667
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1668
+ * @returns Throttled callback handler with a `cancel` method
1669
+ */
1670
+ declare function asyncThrottle<Callback extends GenericAsyncCallback | GenericCallback>(callback: Callback, time?: number): AsyncCancelableCallback<Callback>;
1640
1671
  /**
1641
1672
  * Debounce a function, ensuring it is only called after `time` milliseconds have passed
1642
1673
  *
1643
1674
  * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
1644
1675
  * @param callback Callback to debounce
1645
- * @param time Time in milliseconds to wait before calling the callback _(defaults to match frame rate)_
1646
- * @returns Debounced callback with a `cancel` method
1676
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1677
+ * @returns Debounced callback handler with a `cancel` method
1647
1678
  */
1648
1679
  declare function debounce<Callback extends GenericCallback>(callback: Callback, time?: number): CancelableCallback<Callback>;
1680
+ declare namespace debounce {
1681
+ var async: typeof asyncDebounce;
1682
+ }
1649
1683
  /**
1650
1684
  * Throttle a function, ensuring it is only called once every `time` milliseconds
1651
1685
  * @param callback Callback to throttle
1652
- * @param time Time in milliseconds to wait before calling the callback again _(defaults to match frame rate)_
1653
- * @returns Throttled callback with a `cancel` method
1686
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1687
+ * @returns Throttled callback handler with a `cancel` method
1654
1688
  */
1655
1689
  declare function throttle<Callback extends GenericCallback>(callback: Callback, time?: number): CancelableCallback<Callback>;
1690
+ declare namespace throttle {
1691
+ var async: typeof asyncThrottle;
1692
+ }
1656
1693
  //#endregion
1657
1694
  //#region src/function/once.d.ts
1658
1695
  /**
@@ -4351,4 +4388,4 @@ declare class SizedSet<Value = unknown> extends Set<Value> {
4351
4388
  get(value: Value, update?: boolean): Value | undefined;
4352
4389
  }
4353
4390
  //#endregion
4354
- export { AnyResult, ArrayComparisonSorter, ArrayKeySorter, ArrayOrPlainObject, ArrayPosition, ArrayValueSorter, Asserter, AttemptFlow, AttemptFlowPromise, type Beacon, type BeaconOptions, BuiltIns, CancelableCallback, CancelablePromise, type Color, Constructor, DiffOptions, DiffResult, DiffValue, EqualOptions, Err, EventPosition, ExtendedErr, ExtendedResult, Flow, FlowPromise, FulfilledPromise, GenericAsyncCallback, GenericCallback, type HSLAColor, type HSLColor, HasValue, Key, KeyedValue, type Logger, type Memoized, type MemoizedOptions, MergeOptions, Merger, NestedArray, NestedKeys, NestedPartial, NestedValue, NestedValues, NumericalKeys, NumericalValues, type Observable, type Observer, Ok, OnceAsyncCallback, OnceCallback, PROMISE_ABORT_EVENT, PROMISE_ABORT_OPTIONS, PROMISE_ERROR_NAME, PROMISE_MESSAGE_EXPECTATION_ATTEMPT, PROMISE_MESSAGE_EXPECTATION_RESULT, PROMISE_MESSAGE_EXPECTATION_TIMED, PROMISE_MESSAGE_TIMEOUT, PROMISE_STRATEGY_ALL, PROMISE_STRATEGY_DEFAULT, PROMISE_TYPE_FULFILLED, PROMISE_TYPE_REJECTED, PlainObject, Primitive, PromiseData, PromiseHandlers, PromiseOptions, PromiseParameters, PromiseStrategy, PromiseTimeoutError, PromisesItems, PromisesOptions, PromisesResult, PromisesUnwrapped, PromisesValue, PromisesValues, type Queue, QueueError, type QueueOptions, type Queued, type RGBAColor, type RGBColor, RejectedPromise, RequiredKeys, Result, ResultMatch, RetryError, RetryOptions, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, Simplify, SizedMap, SizedSet, Smushed, SortDirection, Sorter, type Subscription, TemplateOptions, type Time, ToString, TypedArray, Unsmushed, UnwrapValue, assert, attempt, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, fromQuery, toPromise as fromResult, toPromise, getArray, getArrayPosition, getColor, getError, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getTimedPromise, getUuid, getValue, groupBy, handleResult, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, matchResult, max, median, memoize, merge, min, move, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, settlePromise, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
4391
+ export { AnyResult, ArrayComparisonSorter, ArrayKeySorter, ArrayOrPlainObject, ArrayPosition, ArrayValueSorter, Asserter, AsyncCancelableCallback, AttemptFlow, AttemptFlowPromise, type Beacon, type BeaconOptions, BuiltIns, CancelableCallback, CancelablePromise, type Color, Constructor, DiffOptions, DiffResult, DiffValue, EqualOptions, Err, EventPosition, ExtendedErr, ExtendedResult, Flow, FlowPromise, FulfilledPromise, GenericAsyncCallback, GenericCallback, type HSLAColor, type HSLColor, HasValue, Key, KeyedValue, type Logger, type Memoized, type MemoizedOptions, MergeOptions, Merger, NestedArray, NestedKeys, NestedPartial, NestedValue, NestedValues, NumericalKeys, NumericalValues, type Observable, type Observer, Ok, OnceAsyncCallback, OnceCallback, PROMISE_ABORT_EVENT, PROMISE_ABORT_OPTIONS, PROMISE_ERROR_NAME, PROMISE_MESSAGE_EXPECTATION_ATTEMPT, PROMISE_MESSAGE_EXPECTATION_RESULT, PROMISE_MESSAGE_EXPECTATION_TIMED, PROMISE_MESSAGE_TIMEOUT, PROMISE_STRATEGY_ALL, PROMISE_STRATEGY_DEFAULT, PROMISE_TYPE_FULFILLED, PROMISE_TYPE_REJECTED, PlainObject, Primitive, PromiseData, PromiseHandlers, PromiseOptions, PromiseParameters, PromiseStrategy, PromiseTimeoutError, PromisesItems, PromisesOptions, PromisesResult, PromisesUnwrapped, PromisesValue, PromisesValues, type Queue, QueueError, type QueueOptions, type Queued, type RGBAColor, type RGBColor, RejectedPromise, RequiredKeys, Result, ResultMatch, RetryError, RetryOptions, SORT_DIRECTION_ASCENDING, SORT_DIRECTION_DESCENDING, Simplify, SizedMap, SizedSet, Smushed, SortDirection, Sorter, type Subscription, TemplateOptions, type Time, ToString, TypedArray, Unsmushed, UnwrapValue, assert, attempt, attemptFlow, attemptPipe, attemptPromise, average, beacon, between, camelCase, cancelable, capitalize, ceil, chunk, clamp, clone, compact, compare, count, debounce, delay, diff, difference, drop, endsWith, endsWithArray, equal, error, exists, filter, find, flatten, floor, flow, fromQuery, toPromise as fromResult, toPromise, getArray, getArrayPosition, getColor, getError, getForegroundColor, getHexColor, getHexaColor, getHslColor, getHslaColor, getNormalizedHex, getNumber, getRandomBoolean, getRandomCharacters, getRandomColor, getRandomFloat, getRandomHex, getRandomInteger, getRandomItem, getRandomItems, getRgbColor, getRgbaColor, getString, getTimedPromise, getUuid, getValue, groupBy, handleResult, hasValue, hexToHsl, hexToHsla, hexToRgb, hexToRgba, hslToHex, hslToRgb, hslToRgba, ignoreKey, includes, includesArray, indexOf, indexOfArray, insert, intersection, isArrayOrPlainObject, isColor, isConstructor, isEmpty, isError, isFulfilled, isHexColor, isHslColor, isHslLike, isHslaColor, isInstanceOf, isKey, isNonNullable, isNullable, isNullableOrEmpty, isNullableOrWhitespace, isNumber, isNumerical, isObject, isOk, isPlainObject, isPrimitive, isRejected, isResult, isRgbColor, isRgbLike, isRgbaColor, isTypedArray, join, kebabCase, logger, lowerCase, matchResult, max, median, memoize, merge, min, move, noop, ok, omit, once, parse, partition, pascalCase, pick, pipe, promises, push, queue, range, retry, rgbToHex, rgbToHsl, rgbToHsla, round, select, setValue, settlePromise, shuffle, slice, smush, snakeCase, sort, splice, startsWith, startsWithArray, sum, swap, take, template, throttle, timed, times, titleCase, toMap, toQuery, toRecord, toResult, toSet, toggle, trim, truncate, tryDecode, tryEncode, union, unique, unsmush, unwrap, update, upperCase, words };
package/dist/index.mjs CHANGED
@@ -1140,38 +1140,6 @@ function assertIs(condition, message, error) {
1140
1140
  }
1141
1141
  const MESSAGE_VALUE_DEFINED = "Expected value to be defined";
1142
1142
  //#endregion
1143
- //#region src/internal/function/timer.ts
1144
- function getInterval(value) {
1145
- return typeof value === "number" && value > 0 ? value : 0;
1146
- }
1147
- function getTimer(type, callback, time) {
1148
- const interval = getInterval(time);
1149
- function run(now) {
1150
- start ??= now;
1151
- if (interval === 0 || now - start >= interval - OFFSET) {
1152
- start = throttle ? now : void 0;
1153
- callback(...args);
1154
- } else frame = requestAnimationFrame(run);
1155
- }
1156
- const throttle = type === TIMER_THROTTLE;
1157
- let args;
1158
- let frame;
1159
- let start;
1160
- const timer = (...parameters) => {
1161
- timer.cancel();
1162
- args = parameters;
1163
- frame = requestAnimationFrame(run);
1164
- };
1165
- timer.cancel = () => {
1166
- cancelAnimationFrame(frame);
1167
- };
1168
- return timer;
1169
- }
1170
- const OFFSET = 5;
1171
- const TIMER_DEBOUNCE = "debounce";
1172
- const TIMER_THROTTLE = "throttle";
1173
- const TIMER_WAIT = "wait";
1174
- //#endregion
1175
1143
  //#region src/internal/function/misc.ts
1176
1144
  /**
1177
1145
  * A function that does nothing, which can be useful, I guess…
@@ -1399,27 +1367,137 @@ function memoize(callback, options) {
1399
1367
  const DEFAULT_CACHE_SIZE = 1024;
1400
1368
  const SEPARATOR = "_";
1401
1369
  //#endregion
1402
- //#region src/function/index.ts
1370
+ //#region src/internal/function/timer.ts
1371
+ function getAsyncTimer(type, callback, time) {
1372
+ async function run(item) {
1373
+ const now = performance.now();
1374
+ start ??= now;
1375
+ if (interval === 0 || now - start >= interval - OFFSET) {
1376
+ start = throttle ? now : void 0;
1377
+ item.running = true;
1378
+ try {
1379
+ let result = callback(...item.parameters);
1380
+ if (result instanceof Promise) result = await result;
1381
+ item.resolve(result);
1382
+ } catch (error) {
1383
+ item.reject(error);
1384
+ } finally {
1385
+ item.running = false;
1386
+ }
1387
+ } else id = startTimer(() => run(item));
1388
+ }
1389
+ const interval = getInterval(time);
1390
+ const throttle = type === TIMER_THROTTLE;
1391
+ let id;
1392
+ let last;
1393
+ let start;
1394
+ const timer = (...parameters) => {
1395
+ timer.cancel();
1396
+ const next = {
1397
+ parameters,
1398
+ running: false
1399
+ };
1400
+ next.promise = new Promise((resolve, reject) => {
1401
+ next.reject = reject;
1402
+ next.resolve = resolve;
1403
+ });
1404
+ last = next;
1405
+ if (throttle) run(next);
1406
+ else id = startTimer(() => run(next));
1407
+ return next.promise;
1408
+ };
1409
+ timer.cancel = () => {
1410
+ clearTimer(id);
1411
+ if (last != null && !last.running) last.reject();
1412
+ };
1413
+ return timer;
1414
+ }
1415
+ function getInterval(value) {
1416
+ return typeof value === "number" && value > 0 ? value : 0;
1417
+ }
1418
+ function getTimer(type, callback, time) {
1419
+ function run() {
1420
+ const now = performance.now();
1421
+ start ??= now;
1422
+ if (interval === 0 || now - start >= interval - OFFSET) {
1423
+ start = throttle ? now : void 0;
1424
+ callback(...args);
1425
+ } else id = startTimer(run);
1426
+ }
1427
+ const interval = getInterval(time);
1428
+ const throttle = type === TIMER_THROTTLE;
1429
+ let args;
1430
+ let id;
1431
+ let start;
1432
+ const timer = (...parameters) => {
1433
+ timer.cancel();
1434
+ args = parameters;
1435
+ if (throttle) run();
1436
+ else id = startTimer(run);
1437
+ };
1438
+ timer.cancel = () => {
1439
+ clearTimer(id);
1440
+ };
1441
+ return timer;
1442
+ }
1443
+ const OFFSET = 5;
1444
+ const TIMER_DEBOUNCE = "debounce";
1445
+ const TIMER_THROTTLE = "throttle";
1446
+ const TIMER_WAIT = "wait";
1447
+ // istanbul ignore next
1448
+ const clearTimer = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : clearTimeout;
1449
+ // istanbul ignore next
1450
+ const startTimer = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout;
1451
+ //#endregion
1452
+ //#region src/function/limit.ts
1453
+ /**
1454
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
1455
+ *
1456
+ * When called, successful _(finished)_ results will resolve and errors will reject.
1457
+ *
1458
+ * On subsequent calls, existing calls will be canceled _(rejected)_, the timer reset, and will wait another `time` milliseconds before the new call is made _(and so on...)_
1459
+ * @param callback Callback to debounce
1460
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1461
+ * @returns Debounced callback handler with a `cancel` method
1462
+ */
1463
+ function asyncDebounce(callback, time) {
1464
+ return getAsyncTimer(TIMER_DEBOUNCE, callback, time);
1465
+ }
1466
+ /**
1467
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
1468
+ *
1469
+ * When called, successful _(finished)_ results will resolve and errors will reject.
1470
+ *
1471
+ * On subsequent calls, existing calls will be canceled _(rejected)_ and will wait until the next valid time to call the callback again _(and so on...)_
1472
+ * @param callback Callback to throttle
1473
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1474
+ * @returns Throttled callback handler with a `cancel` method
1475
+ */
1476
+ function asyncThrottle(callback, time) {
1477
+ return getAsyncTimer(TIMER_THROTTLE, callback, time);
1478
+ }
1403
1479
  /**
1404
1480
  * Debounce a function, ensuring it is only called after `time` milliseconds have passed
1405
1481
  *
1406
1482
  * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
1407
1483
  * @param callback Callback to debounce
1408
- * @param time Time in milliseconds to wait before calling the callback _(defaults to match frame rate)_
1409
- * @returns Debounced callback with a `cancel` method
1484
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
1485
+ * @returns Debounced callback handler with a `cancel` method
1410
1486
  */
1411
1487
  function debounce(callback, time) {
1412
1488
  return getTimer(TIMER_DEBOUNCE, callback, time);
1413
1489
  }
1490
+ debounce.async = asyncDebounce;
1414
1491
  /**
1415
1492
  * Throttle a function, ensuring it is only called once every `time` milliseconds
1416
1493
  * @param callback Callback to throttle
1417
- * @param time Time in milliseconds to wait before calling the callback again _(defaults to match frame rate)_
1418
- * @returns Throttled callback with a `cancel` method
1494
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
1495
+ * @returns Throttled callback handler with a `cancel` method
1419
1496
  */
1420
1497
  function throttle(callback, time) {
1421
1498
  return getTimer(TIMER_THROTTLE, callback, time);
1422
1499
  }
1500
+ throttle.async = asyncThrottle;
1423
1501
  //#endregion
1424
1502
  //#region src/function/once.ts
1425
1503
  /**
@@ -2313,7 +2391,7 @@ function cloneValue(value, depth, references) {
2313
2391
  case value instanceof Date: return new Date(value.getTime());
2314
2392
  case value instanceof RegExp: return cloneRegularExpression(value, depth, references);
2315
2393
  case value instanceof Map: return cloneMap(value, depth, references);
2316
- case value instanceof Node: return cloneNode(value, depth, references);
2394
+ case typeof Node !== "undefined" && value instanceof Node: return cloneNode(value, depth, references);
2317
2395
  case value instanceof Set: return cloneSet(value, depth, references);
2318
2396
  case isArrayOrPlainObject(value): return clonePlainObject(value, depth, references);
2319
2397
  case isTypedArray(value): return cloneTypedArray(value, depth, references);
@@ -1,10 +1,11 @@
1
- import { CancelableCallback, GenericCallback } from "../../models.mjs";
1
+ import { AsyncCancelableCallback, CancelableCallback, GenericAsyncCallback, GenericCallback } from "../../models.mjs";
2
2
 
3
3
  //#region src/internal/function/timer.d.ts
4
4
  type TimerType = 'debounce' | 'throttle' | 'wait';
5
+ declare function getAsyncTimer<Callback extends GenericAsyncCallback | GenericCallback>(type: TimerType, callback: Callback, time?: number): AsyncCancelableCallback<Callback>;
5
6
  declare function getTimer<Callback extends GenericCallback>(type: TimerType, callback: Callback, time?: number): CancelableCallback<Callback>;
6
7
  declare const TIMER_DEBOUNCE: TimerType;
7
8
  declare const TIMER_THROTTLE: TimerType;
8
9
  declare const TIMER_WAIT: TimerType;
9
10
  //#endregion
10
- export { TIMER_DEBOUNCE, TIMER_THROTTLE, TIMER_WAIT, getTimer };
11
+ export { TIMER_DEBOUNCE, TIMER_THROTTLE, TIMER_WAIT, getAsyncTimer, getTimer };
@@ -1,27 +1,73 @@
1
1
  //#region src/internal/function/timer.ts
2
+ function getAsyncTimer(type, callback, time) {
3
+ async function run(item) {
4
+ const now = performance.now();
5
+ start ??= now;
6
+ if (interval === 0 || now - start >= interval - OFFSET) {
7
+ start = throttle ? now : void 0;
8
+ item.running = true;
9
+ try {
10
+ let result = callback(...item.parameters);
11
+ if (result instanceof Promise) result = await result;
12
+ item.resolve(result);
13
+ } catch (error) {
14
+ item.reject(error);
15
+ } finally {
16
+ item.running = false;
17
+ }
18
+ } else id = startTimer(() => run(item));
19
+ }
20
+ const interval = getInterval(time);
21
+ const throttle = type === TIMER_THROTTLE;
22
+ let id;
23
+ let last;
24
+ let start;
25
+ const timer = (...parameters) => {
26
+ timer.cancel();
27
+ const next = {
28
+ parameters,
29
+ running: false
30
+ };
31
+ next.promise = new Promise((resolve, reject) => {
32
+ next.reject = reject;
33
+ next.resolve = resolve;
34
+ });
35
+ last = next;
36
+ if (throttle) run(next);
37
+ else id = startTimer(() => run(next));
38
+ return next.promise;
39
+ };
40
+ timer.cancel = () => {
41
+ clearTimer(id);
42
+ if (last != null && !last.running) last.reject();
43
+ };
44
+ return timer;
45
+ }
2
46
  function getInterval(value) {
3
47
  return typeof value === "number" && value > 0 ? value : 0;
4
48
  }
5
49
  function getTimer(type, callback, time) {
6
- const interval = getInterval(time);
7
- function run(now) {
50
+ function run() {
51
+ const now = performance.now();
8
52
  start ??= now;
9
53
  if (interval === 0 || now - start >= interval - OFFSET) {
10
54
  start = throttle ? now : void 0;
11
55
  callback(...args);
12
- } else frame = requestAnimationFrame(run);
56
+ } else id = startTimer(run);
13
57
  }
58
+ const interval = getInterval(time);
14
59
  const throttle = type === TIMER_THROTTLE;
15
60
  let args;
16
- let frame;
61
+ let id;
17
62
  let start;
18
63
  const timer = (...parameters) => {
19
64
  timer.cancel();
20
65
  args = parameters;
21
- frame = requestAnimationFrame(run);
66
+ if (throttle) run();
67
+ else id = startTimer(run);
22
68
  };
23
69
  timer.cancel = () => {
24
- cancelAnimationFrame(frame);
70
+ clearTimer(id);
25
71
  };
26
72
  return timer;
27
73
  }
@@ -29,5 +75,9 @@ const OFFSET = 5;
29
75
  const TIMER_DEBOUNCE = "debounce";
30
76
  const TIMER_THROTTLE = "throttle";
31
77
  const TIMER_WAIT = "wait";
78
+ // istanbul ignore next
79
+ const clearTimer = typeof cancelAnimationFrame === "function" ? cancelAnimationFrame : clearTimeout;
80
+ // istanbul ignore next
81
+ const startTimer = typeof requestAnimationFrame === "function" ? requestAnimationFrame : setTimeout;
32
82
  //#endregion
33
- export { TIMER_DEBOUNCE, TIMER_THROTTLE, TIMER_WAIT, getTimer };
83
+ export { TIMER_DEBOUNCE, TIMER_THROTTLE, TIMER_WAIT, getAsyncTimer, getTimer };
package/dist/models.d.mts CHANGED
@@ -3,6 +3,15 @@
3
3
  * A generic array or object
4
4
  */
5
5
  type ArrayOrPlainObject = unknown[] | Record<PropertyKey, unknown>;
6
+ /**
7
+ * An asynchronous callback that can be canceled
8
+ */
9
+ type AsyncCancelableCallback<Callback extends GenericAsyncCallback | GenericCallback> = (ReturnType<Callback> extends Promise<any> ? (...args: Parameters<Callback>) => Promise<Awaited<ReturnType<Callback>>> : (...args: Parameters<Callback>) => Promise<ReturnType<Callback>>) & {
10
+ /**
11
+ * Cancel the callback
12
+ */
13
+ cancel: () => void;
14
+ };
6
15
  /**
7
16
  * For mathicng any `void`, `Date`, primitive, or `RegExp` values
8
17
  *
@@ -10,7 +19,7 @@ type ArrayOrPlainObject = unknown[] | Record<PropertyKey, unknown>;
10
19
  */
11
20
  type BuiltIns = void | Date | Primitive | RegExp;
12
21
  /**
13
- * An extend callback that can be canceled
22
+ * A synchronous callback that can be canceled
14
23
  */
15
24
  type CancelableCallback<Callback extends GenericCallback> = Callback & {
16
25
  /**
@@ -135,4 +144,4 @@ type ToString<Value> = Value extends string | number ? `${Value}` : never;
135
144
  */
136
145
  type TypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array;
137
146
  //#endregion
138
- export { ArrayOrPlainObject, BuiltIns, CancelableCallback, Constructor, EventPosition, GenericAsyncCallback, GenericCallback, Key, KeyedValue, NestedArray, NestedKeys, NestedPartial, NestedValue, NestedValues, NumericalKeys, NumericalValues, OnceAsyncCallback, OnceCallback, PlainObject, Primitive, RequiredKeys, Simplify, ToString, TypedArray };
147
+ export { ArrayOrPlainObject, AsyncCancelableCallback, BuiltIns, CancelableCallback, Constructor, EventPosition, GenericAsyncCallback, GenericCallback, Key, KeyedValue, NestedArray, NestedKeys, NestedPartial, NestedValue, NestedValues, NumericalKeys, NumericalValues, OnceAsyncCallback, OnceCallback, PlainObject, Primitive, RequiredKeys, Simplify, ToString, TypedArray };
@@ -103,7 +103,7 @@ function cloneValue(value, depth, references) {
103
103
  case value instanceof Date: return new Date(value.getTime());
104
104
  case value instanceof RegExp: return cloneRegularExpression(value, depth, references);
105
105
  case value instanceof Map: return cloneMap(value, depth, references);
106
- case value instanceof Node: return cloneNode(value, depth, references);
106
+ case typeof Node !== "undefined" && value instanceof Node: return cloneNode(value, depth, references);
107
107
  case value instanceof Set: return cloneSet(value, depth, references);
108
108
  case isArrayOrPlainObject(value): return clonePlainObject(value, depth, references);
109
109
  case isTypedArray(value): return cloneTypedArray(value, depth, references);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/atoms",
3
- "version": "0.169.0",
3
+ "version": "0.171.0",
4
4
  "description": "Atomic utilities for making your JavaScript better.",
5
5
  "keywords": [
6
6
  "helper",
@@ -76,6 +76,10 @@
76
76
  "types": "./dist/function/assert.d.mts",
77
77
  "default": "./dist/function/assert.mjs"
78
78
  },
79
+ "./function/limit": {
80
+ "types": "./dist/function/limit.d.mts",
81
+ "default": "./dist/function/limit.mjs"
82
+ },
79
83
  "./function/once": {
80
84
  "types": "./dist/function/once.d.mts",
81
85
  "default": "./dist/function/once.mjs"
@@ -221,7 +225,6 @@
221
225
  "tsdown:build": "npx tsdown -c ./tsdown.config.ts",
222
226
  "tsdown:watch": "npx tsdown -c ./tsdown.config.ts --watch",
223
227
  "test": "npx vp test run --coverage",
224
- "test:leak": "npx vp test run --detect-async-leaks --coverage",
225
228
  "watch": "npx vite build --watch"
226
229
  },
227
230
  "devDependencies": {
@@ -1,41 +1,2 @@
1
- import {getTimer, TIMER_DEBOUNCE, TIMER_THROTTLE} from '../internal/function/timer';
2
- import type {CancelableCallback, GenericCallback} from '../models';
3
-
4
- // #region Functions
5
-
6
- /**
7
- * Debounce a function, ensuring it is only called after `time` milliseconds have passed
8
- *
9
- * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
10
- * @param callback Callback to debounce
11
- * @param time Time in milliseconds to wait before calling the callback _(defaults to match frame rate)_
12
- * @returns Debounced callback with a `cancel` method
13
- */
14
- export function debounce<Callback extends GenericCallback>(
15
- callback: Callback,
16
- time?: number,
17
- ): CancelableCallback<Callback> {
18
- return getTimer(TIMER_DEBOUNCE, callback, time);
19
- }
20
-
21
- /**
22
- * Throttle a function, ensuring it is only called once every `time` milliseconds
23
- * @param callback Callback to throttle
24
- * @param time Time in milliseconds to wait before calling the callback again _(defaults to match frame rate)_
25
- * @returns Throttled callback with a `cancel` method
26
- */
27
- export function throttle<Callback extends GenericCallback>(
28
- callback: Callback,
29
- time?: number,
30
- ): CancelableCallback<Callback> {
31
- return getTimer(TIMER_THROTTLE, callback, time);
32
- }
33
-
34
- // #endregion
35
-
36
- // #region Exports
37
-
38
1
  export {noop} from '../internal/function/misc';
39
2
  export {memoize, type Memoized, type MemoizedOptions} from './memoize';
40
-
41
- // #endregion
@@ -0,0 +1,77 @@
1
+ import {getAsyncTimer, getTimer, TIMER_DEBOUNCE, TIMER_THROTTLE} from '../internal/function/timer';
2
+ import type {
3
+ AsyncCancelableCallback,
4
+ CancelableCallback,
5
+ GenericAsyncCallback,
6
+ GenericCallback,
7
+ } from '../models';
8
+
9
+ // #region Functions
10
+
11
+ /**
12
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
13
+ *
14
+ * When called, successful _(finished)_ results will resolve and errors will reject.
15
+ *
16
+ * On subsequent calls, existing calls will be canceled _(rejected)_, the timer reset, and will wait another `time` milliseconds before the new call is made _(and so on...)_
17
+ * @param callback Callback to debounce
18
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
19
+ * @returns Debounced callback handler with a `cancel` method
20
+ */
21
+ function asyncDebounce<Callback extends GenericAsyncCallback | GenericCallback>(
22
+ callback: Callback,
23
+ time?: number,
24
+ ): AsyncCancelableCallback<Callback> {
25
+ return getAsyncTimer(TIMER_DEBOUNCE, callback, time);
26
+ }
27
+
28
+ /**
29
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
30
+ *
31
+ * When called, successful _(finished)_ results will resolve and errors will reject.
32
+ *
33
+ * On subsequent calls, existing calls will be canceled _(rejected)_ and will wait until the next valid time to call the callback again _(and so on...)_
34
+ * @param callback Callback to throttle
35
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
36
+ * @returns Throttled callback handler with a `cancel` method
37
+ */
38
+ function asyncThrottle<Callback extends GenericAsyncCallback | GenericCallback>(
39
+ callback: Callback,
40
+ time?: number,
41
+ ): AsyncCancelableCallback<Callback> {
42
+ return getAsyncTimer(TIMER_THROTTLE, callback, time);
43
+ }
44
+
45
+ /**
46
+ * Debounce a function, ensuring it is only called after `time` milliseconds have passed
47
+ *
48
+ * On subsequent calls, the timer is reset and will wait another `time` milliseconds _(and so on...)_
49
+ * @param callback Callback to debounce
50
+ * @param time Time in milliseconds to wait before calling the callback _(defaults to `0`; e.g., as soon as possible)_
51
+ * @returns Debounced callback handler with a `cancel` method
52
+ */
53
+ export function debounce<Callback extends GenericCallback>(
54
+ callback: Callback,
55
+ time?: number,
56
+ ): CancelableCallback<Callback> {
57
+ return getTimer(TIMER_DEBOUNCE, callback, time);
58
+ }
59
+
60
+ debounce.async = asyncDebounce;
61
+
62
+ /**
63
+ * Throttle a function, ensuring it is only called once every `time` milliseconds
64
+ * @param callback Callback to throttle
65
+ * @param time Time in milliseconds to wait before calling the callback again _(defaults to `0`; e.g., as soon as possible)_
66
+ * @returns Throttled callback handler with a `cancel` method
67
+ */
68
+ export function throttle<Callback extends GenericCallback>(
69
+ callback: Callback,
70
+ time?: number,
71
+ ): CancelableCallback<Callback> {
72
+ return getTimer(TIMER_THROTTLE, callback, time);
73
+ }
74
+
75
+ throttle.async = asyncThrottle;
76
+
77
+ // #endregion
package/src/index.ts CHANGED
@@ -10,6 +10,7 @@ export * from './array/unique';
10
10
 
11
11
  export * from './function/assert';
12
12
  export * from './function/index';
13
+ export * from './function/limit';
13
14
  export * from './function/once';
14
15
  export * from './function/retry';
15
16
  export * from './function/work';
@@ -1,13 +1,101 @@
1
- import type {CancelableCallback, GenericCallback} from '../../models';
1
+ import type {
2
+ AsyncCancelableCallback,
3
+ CancelableCallback,
4
+ GenericAsyncCallback,
5
+ GenericCallback,
6
+ } from '../../models';
2
7
 
3
8
  // #region Types
4
9
 
10
+ type AsyncItem = {
11
+ parameters: unknown[];
12
+ promise: Promise<unknown>;
13
+ reject: (reason?: unknown) => void;
14
+ resolve: (value?: unknown) => void;
15
+ running: boolean;
16
+ };
17
+
5
18
  type TimerType = 'debounce' | 'throttle' | 'wait';
6
19
 
7
20
  // #endregion
8
21
 
9
22
  // #region Functions
10
23
 
24
+ export function getAsyncTimer<Callback extends GenericAsyncCallback | GenericCallback>(
25
+ type: TimerType,
26
+ callback: Callback,
27
+ time?: number,
28
+ ): AsyncCancelableCallback<Callback> {
29
+ async function run(item: AsyncItem): Promise<void> {
30
+ const now = performance.now();
31
+
32
+ start ??= now;
33
+
34
+ if (interval === 0 || now - start >= interval - OFFSET) {
35
+ start = throttle ? now : undefined;
36
+
37
+ item.running = true;
38
+
39
+ try {
40
+ let result = callback(...item.parameters);
41
+
42
+ if (result instanceof Promise) {
43
+ result = await result;
44
+ }
45
+
46
+ item.resolve(result);
47
+ } catch (error) {
48
+ item.reject(error);
49
+ } finally {
50
+ item.running = false;
51
+ }
52
+ } else {
53
+ id = startTimer(() => run(item));
54
+ }
55
+ }
56
+
57
+ const interval = getInterval(time);
58
+ const throttle = type === TIMER_THROTTLE;
59
+
60
+ let id: number;
61
+ let last: AsyncItem;
62
+ let start: number | undefined;
63
+
64
+ const timer = (...parameters: Parameters<Callback>): Promise<unknown> => {
65
+ timer.cancel();
66
+
67
+ const next: AsyncItem = {
68
+ parameters,
69
+ running: false,
70
+ } as never;
71
+
72
+ next.promise = new Promise<unknown>((resolve, reject) => {
73
+ next.reject = reject;
74
+ next.resolve = resolve;
75
+ });
76
+
77
+ last = next;
78
+
79
+ if (throttle) {
80
+ run(next);
81
+ } else {
82
+ id = startTimer(() => run(next));
83
+ }
84
+
85
+ return next.promise;
86
+ };
87
+
88
+ timer.cancel = (): void => {
89
+ clearTimer(id);
90
+
91
+ if (last != null && !last.running) {
92
+ last.reject();
93
+ }
94
+ };
95
+
96
+ return timer as AsyncCancelableCallback<Callback>;
97
+ }
98
+
11
99
  function getInterval(value: unknown): number {
12
100
  return typeof value === 'number' && value > 0 ? value : 0;
13
101
  }
@@ -17,9 +105,9 @@ export function getTimer<Callback extends GenericCallback>(
17
105
  callback: Callback,
18
106
  time?: number,
19
107
  ): CancelableCallback<Callback> {
20
- const interval = getInterval(time);
108
+ function run(): void {
109
+ const now = performance.now();
21
110
 
22
- function run(now: DOMHighResTimeStamp): void {
23
111
  start ??= now;
24
112
 
25
113
  if (interval === 0 || now - start >= interval - OFFSET) {
@@ -27,25 +115,31 @@ export function getTimer<Callback extends GenericCallback>(
27
115
 
28
116
  callback(...args);
29
117
  } else {
30
- frame = requestAnimationFrame(run);
118
+ id = startTimer(run);
31
119
  }
32
120
  }
33
121
 
122
+ const interval = getInterval(time);
34
123
  const throttle = type === TIMER_THROTTLE;
35
124
 
36
125
  let args: Parameters<Callback>;
37
- let frame: DOMHighResTimeStamp | undefined;
38
- let start: DOMHighResTimeStamp | undefined;
126
+ let id: number;
127
+ let start: number | undefined;
39
128
 
40
129
  const timer = (...parameters: Parameters<Callback>): void => {
41
130
  timer.cancel();
42
131
 
43
132
  args = parameters;
44
- frame = requestAnimationFrame(run);
133
+
134
+ if (throttle) {
135
+ run();
136
+ } else {
137
+ id = startTimer(run);
138
+ }
45
139
  };
46
140
 
47
141
  timer.cancel = (): void => {
48
- cancelAnimationFrame(frame!);
142
+ clearTimer(id);
49
143
  };
50
144
 
51
145
  return timer as CancelableCallback<Callback>;
@@ -63,4 +157,10 @@ export const TIMER_THROTTLE: TimerType = 'throttle';
63
157
 
64
158
  export const TIMER_WAIT: TimerType = 'wait';
65
159
 
160
+ // istanbul ignore next
161
+ const clearTimer = typeof cancelAnimationFrame === 'function' ? cancelAnimationFrame : clearTimeout;
162
+
163
+ // istanbul ignore next
164
+ const startTimer = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : setTimeout;
165
+
66
166
  // #endregion
package/src/models.ts CHANGED
@@ -5,6 +5,19 @@
5
5
  */
6
6
  export type ArrayOrPlainObject = unknown[] | Record<PropertyKey, unknown>;
7
7
 
8
+ /**
9
+ * An asynchronous callback that can be canceled
10
+ */
11
+ export type AsyncCancelableCallback<Callback extends GenericAsyncCallback | GenericCallback> =
12
+ (ReturnType<Callback> extends Promise<any>
13
+ ? (...args: Parameters<Callback>) => Promise<Awaited<ReturnType<Callback>>>
14
+ : (...args: Parameters<Callback>) => Promise<ReturnType<Callback>>) & {
15
+ /**
16
+ * Cancel the callback
17
+ */
18
+ cancel: () => void;
19
+ };
20
+
8
21
  /**
9
22
  * For mathicng any `void`, `Date`, primitive, or `RegExp` values
10
23
  *
@@ -13,7 +26,7 @@ export type ArrayOrPlainObject = unknown[] | Record<PropertyKey, unknown>;
13
26
  export type BuiltIns = void | Date | Primitive | RegExp;
14
27
 
15
28
  /**
16
- * An extend callback that can be canceled
29
+ * A synchronous callback that can be canceled
17
30
  */
18
31
  export type CancelableCallback<Callback extends GenericCallback> = Callback & {
19
32
  /**
@@ -243,7 +243,7 @@ function cloneValue(value: unknown, depth: number, references: WeakMap<WeakKey,
243
243
  case value instanceof Map:
244
244
  return cloneMap(value, depth, references);
245
245
 
246
- case value instanceof Node:
246
+ case typeof Node !== 'undefined' && value instanceof Node:
247
247
  return cloneNode(value, depth, references);
248
248
 
249
249
  case value instanceof Set: