@fast-china/utils 2.1.10 → 2.1.11

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +5 -2
  3. package/README.zh.md +5 -2
  4. package/dist/array/index.mjs +21 -21
  5. package/dist/array/index.mjs.map +1 -1
  6. package/dist/async/index.mjs +32 -32
  7. package/dist/async/index.mjs.map +1 -1
  8. package/dist/base64/index.mjs +44 -51
  9. package/dist/base64/index.mjs.map +1 -1
  10. package/dist/color/index.mjs +33 -33
  11. package/dist/color/index.mjs.map +1 -1
  12. package/dist/crypto/index.mjs +153 -155
  13. package/dist/crypto/index.mjs.map +1 -1
  14. package/dist/date/index.mjs +79 -46
  15. package/dist/date/index.mjs.map +1 -1
  16. package/dist/dom/style.mjs +7 -7
  17. package/dist/dom/style.mjs.map +1 -1
  18. package/dist/env/index.mjs +9 -14
  19. package/dist/env/index.mjs.map +1 -1
  20. package/dist/function/index.mjs +4 -4
  21. package/dist/function/index.mjs.map +1 -1
  22. package/dist/identity/index.mjs +7 -7
  23. package/dist/identity/index.mjs.map +1 -1
  24. package/dist/index.d.mts +371 -366
  25. package/dist/index.global.min.js +2 -2
  26. package/dist/index.global.min.js.map +1 -1
  27. package/dist/internal/text.mjs +70 -26
  28. package/dist/internal/text.mjs.map +1 -1
  29. package/dist/logger/index.mjs +12 -13
  30. package/dist/logger/index.mjs.map +1 -1
  31. package/dist/number/index.mjs +63 -42
  32. package/dist/number/index.mjs.map +1 -1
  33. package/dist/object/index.mjs +32 -31
  34. package/dist/object/index.mjs.map +1 -1
  35. package/dist/storage/index.mjs +58 -63
  36. package/dist/storage/index.mjs.map +1 -1
  37. package/dist/string/index.mjs +60 -64
  38. package/dist/string/index.mjs.map +1 -1
  39. package/dist/vue/breakpoints.mjs +14 -10
  40. package/dist/vue/breakpoints.mjs.map +1 -1
  41. package/dist/vue/element-size.mjs +4 -4
  42. package/dist/vue/element-size.mjs.map +1 -1
  43. package/dist/vue/emits.mjs +7 -7
  44. package/dist/vue/emits.mjs.map +1 -1
  45. package/dist/vue/event-listener.mjs +5 -5
  46. package/dist/vue/event-listener.mjs.map +1 -1
  47. package/dist/vue/expose.mjs +3 -3
  48. package/dist/vue/expose.mjs.map +1 -1
  49. package/dist/vue/func.mjs +2 -2
  50. package/dist/vue/func.mjs.map +1 -1
  51. package/dist/vue/install.mjs +24 -24
  52. package/dist/vue/install.mjs.map +1 -1
  53. package/dist/vue/now.mjs +4 -5
  54. package/dist/vue/now.mjs.map +1 -1
  55. package/dist/vue/props.mjs +5 -5
  56. package/dist/vue/props.mjs.map +1 -1
  57. package/dist/vue/render.mjs +2 -2
  58. package/dist/vue/render.mjs.map +1 -1
  59. package/dist/vue/resize-observer.mjs +4 -6
  60. package/dist/vue/resize-observer.mjs.map +1 -1
  61. package/dist/vue/slots.mjs.map +1 -1
  62. package/dist/vue/transition.mjs +5 -7
  63. package/dist/vue/transition.mjs.map +1 -1
  64. package/dist/vue/window-size.mjs +2 -4
  65. package/dist/vue/window-size.mjs.map +1 -1
  66. package/dist/vue/with.mjs +1 -1
  67. package/dist/vue/with.mjs.map +1 -1
  68. package/package.json +2 -1
  69. package/dist/internal/runtime.mjs +0 -32
  70. package/dist/internal/runtime.mjs.map +0 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,27 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and releases should follow [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [2.1.11] - 2026-10-07
8
+
9
+ ### Fixed
10
+
11
+ - Replace internal query codecs with native encodeURIComponent/decodeURIComponent while preserving form escaping and space options. Malformed percent-encoded queries and lone surrogates passed to query encoding now throw URIError; raw unescaped surrogates follow native decoding behavior.
12
+
13
+ - Format default Chinese relative times and default byte amounts internally without Intl; retain native formatting for explicit locales and use standard casing when no locale is supplied.
14
+
15
+ - Support legacy MediaQueryList listeners with scope cleanup and check only the SubtleCrypto methods required by each operation.
16
+
17
+ - Use one internal UTF-8 implementation independently of native TextEncoder or TextDecoder, preserving strict decoding, BOM handling, and lone-surrogate replacement for Base64, storage codecs, and Web Crypto text.
18
+ - Call host APIs through their native identifiers, including `uni`, `window`, `document`, `navigator`, `crypto`, `process`, `Intl.Segmenter`, and `ResizeObserver`, while retaining call-time capability checks.
19
+ - Remove Object.hasOwn, Array/String.at, URLSearchParams, and import-time globalThis requirements from core utilities; use native URI component functions for query encoding/decoding without platform polyfills.
20
+ - Retain ES2022 output syntax and check optional platform capabilities at call time; no older browser syntax target is implied.
21
+
22
+ ### Documentation and Tooling
23
+
24
+ - Standardize SDK-generated error messages in English while preserving error types, names, causes, and caller/platform errors.
25
+ - Correct TSDoc labels and runtime descriptions; synchronize bilingual documentation with native query error semantics.
26
+ - Include Node, DCloud, DOM, and worker importScripts types for development without injecting runtime polyfills.
27
+
7
28
  ## [2.1.10] - 2026-09-27
8
29
 
9
30
  ### Added
@@ -155,6 +176,7 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
155
176
 
156
177
  - Added authenticated ciphertext validation, bounded crypto parameters and payloads, unbiased Web Crypto randomness, prototype-safe query/object transforms, and namespace-scoped Storage cleanup.
157
178
 
179
+ [2.1.11]: https://gitee.com/FastDotnet/fast.utils/compare/v2.1.10...v2.1.11
158
180
  [2.1.10]: https://gitee.com/FastDotnet/fast.utils/compare/v2.1.9...v2.1.10
159
181
  [2.1.9]: https://gitee.com/FastDotnet/fast.utils/compare/v2.1.8...v2.1.9
160
182
  [2.1.8]: https://gitee.com/FastDotnet/fast.utils/compare/v2.1.7...v2.1.8
package/README.md CHANGED
@@ -73,14 +73,17 @@ Parameter validation or a pre-aborted signal may throw synchronously; cancellati
73
73
 
74
74
  The `object` module includes dependency-free deep cloning and equality plus predicate-based property selection. Array utilities include a SameValueZero symmetric difference, while `once` preserves the first return value, Promise identity, or synchronous error.
75
75
 
76
+ SDK-generated error messages are in English. Branch on error types or names rather than matching message text; caller and platform errors are propagated unchanged.
77
+
76
78
  ## Runtime contract
77
79
 
78
80
  - The package-manager entry is pure ESM; the CDN entry is a separately minified IIFE.
79
- - ES2022 modern browsers and WebViews.
81
+ - ESM and IIFE output targets ES2022 syntax; platform API availability is checked separately.
80
82
  - Vue 3.5.11 or newer through a required peer dependency.
81
- - uni-app through call-time detection of runtime-injected `uni` and App-Plus `plus`, with global-property fallbacks.
83
+ - uni-app through guarded, direct `uni.xxx` calls; App-Plus detection checks `typeof plus` directly.
82
84
  - No import-time access to `window`, Storage, or `uni`; unsupported calls fail explicitly.
83
85
  - Web Crypto, URL, Intl, TextEncoder, and related platform capabilities are not polyfilled.
86
+ - Text operations always use an internal UTF-8 implementation without TextEncoder / TextDecoder or global changes; invalid UTF-8 throws TypeError.
84
87
 
85
88
  ## Documentation
86
89
 
package/README.zh.md CHANGED
@@ -73,14 +73,17 @@ console.log(encoded, size);
73
73
 
74
74
  `object` 模块提供不依赖第三方库的深复制、深度比较和按条件筛选属性能力。数组工具支持 SameValueZero 对称差集,`once` 则会保留第一次调用的返回值、Promise 引用或同步错误。
75
75
 
76
+ SDK 自身生成的报错提示统一使用英文。错误处理应依据异常类型或名称,不匹配消息文本;调用方和平台错误保持原样传播。
77
+
76
78
  ## 运行时契约
77
79
 
78
80
  - 包管理器入口为纯 ESM;CDN 入口为单独压缩的 IIFE。
79
- - 面向 ES2022 现代浏览器与 WebView。
81
+ - ESM 与 IIFE 产物使用 ES2022 语法目标;平台 API 是否可用需独立判断。
80
82
  - Vue 3.5.11 及以上版本通过必须安装的 Peer Dependency 接入。
81
- - 调用时检测运行时注入的 `uni` 和 App-Plus `plus`,并兼容对应全局属性。
83
+ - 调用时检查并直接使用 `uni.xxx`;App-Plus 直接通过 `typeof plus` 判断。
82
84
  - 导入阶段不访问 `window`、Storage 或 `uni`;不支持的调用明确失败。
83
85
  - 不注入 Web Crypto、URL、Intl、TextEncoder 等 Polyfill。
86
+ - 文本编解码统一使用内部 UTF-8 实现,不依赖 TextEncoder / TextDecoder,不修改全局对象;非法 UTF-8 抛出 TypeError。
84
87
 
85
88
  ## 文档
86
89
 
@@ -2,14 +2,14 @@
2
2
  /**
3
3
  * 将只读数组按固定大小分组。
4
4
  *
5
- * @typeParam Item - 数组项类型。
6
- * @param items - 不会被修改的输入数组。
5
+ * @typeParam Item - 数组项类型
6
+ * @param items - 不会被修改的输入数组
7
7
  * @param size - 每组最多包含的项目数,必须是正安全整数。
8
8
  * @returns 新建的二维数组;最后一组可能小于 `size`。
9
9
  * @throws `RangeError` 当 `size` 不是正安全整数。
10
10
  */
11
11
  function chunk(items, size) {
12
- if (!Number.isSafeInteger(size) || size <= 0) throw new RangeError("`size` 必须是正安全整数。");
12
+ if (!Number.isSafeInteger(size) || size <= 0) throw new RangeError("`size` must be a positive safe integer.");
13
13
  const result = [];
14
14
  for (let index = 0; index < items.length; index += size) result.push(items.slice(index, index + size));
15
15
  return result;
@@ -17,8 +17,8 @@ function chunk(items, size) {
17
17
  /**
18
18
  * 删除数组中的 `null` 与 `undefined`,保留 `false`、`0` 和空字符串。
19
19
  *
20
- * @param items - 可包含空值的只读数组。
21
- * @returns 保持原顺序的新数组。
20
+ * @param items - 可包含空值的只读数组
21
+ * @returns 保持原顺序的新数组
22
22
  */
23
23
  function removeNullishValues(items) {
24
24
  return items.filter((item) => item !== null && item !== void 0);
@@ -26,7 +26,7 @@ function removeNullishValues(items) {
26
26
  /**
27
27
  * 使用 JavaScript `Set` 的 SameValueZero 语义去重。
28
28
  *
29
- * @param items - 不会被修改的输入数组。
29
+ * @param items - 不会被修改的输入数组
30
30
  * @returns 保留每个值首次出现顺序的新数组;稀疏数组空位被忽略。
31
31
  */
32
32
  function unique(items) {
@@ -44,8 +44,8 @@ function unique(items) {
44
44
  /**
45
45
  * 按选择器返回的键去重。
46
46
  *
47
- * @param items - 不会被修改的输入数组。
48
- * @param selectKey - 接收项目与索引并返回去重键的函数。
47
+ * @param items - 不会被修改的输入数组
48
+ * @param selectKey - 接收项目与索引并返回去重键的函数
49
49
  * @returns 保留每个键首次出现项目的新数组;稀疏数组空位被忽略。
50
50
  */
51
51
  function uniqueBy(items, selectKey) {
@@ -64,8 +64,8 @@ function uniqueBy(items, selectKey) {
64
64
  /**
65
65
  * 按选择器结果分组。
66
66
  *
67
- * @param items - 不会被修改的输入数组。
68
- * @param selectKey - 返回任意 `Map` 键的函数。
67
+ * @param items - 不会被修改的输入数组
68
+ * @param selectKey - 返回任意 `Map` 键的函数
69
69
  * @returns 按键首次出现顺序排列的 `Map`;每个分组保持输入顺序,稀疏空位被忽略。
70
70
  */
71
71
  function groupBy(items, selectKey) {
@@ -81,8 +81,8 @@ function groupBy(items, selectKey) {
81
81
  /**
82
82
  * 按谓词把数组拆分为匹配项和非匹配项。
83
83
  *
84
- * @param items - 不会被修改的输入数组。
85
- * @param predicate - 接收项目与索引的判断函数。
84
+ * @param items - 不会被修改的输入数组
85
+ * @param predicate - 接收项目与索引的判断函数
86
86
  * @returns 二元组:第一项匹配谓词,第二项不匹配;两组都保持原顺序并忽略稀疏空位。
87
87
  */
88
88
  function partition(items, predicate) {
@@ -94,8 +94,8 @@ function partition(items, predicate) {
94
94
  /**
95
95
  * 返回只出现在左侧数组中的不同值。
96
96
  *
97
- * @param left - 主输入数组。
98
- * @param right - 需要排除的值。
97
+ * @param left - 主输入数组
98
+ * @param right - 需要排除的值
99
99
  * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。
100
100
  */
101
101
  function difference(left, right) {
@@ -105,8 +105,8 @@ function difference(left, right) {
105
105
  /**
106
106
  * 返回两个数组共有的不同值。
107
107
  *
108
- * @param left - 决定结果顺序的数组。
109
- * @param right - 用于成员判断的数组。
108
+ * @param left - 决定结果顺序的数组
109
+ * @param right - 用于成员判断的数组
110
110
  * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。
111
111
  */
112
112
  function intersection(left, right) {
@@ -116,8 +116,8 @@ function intersection(left, right) {
116
116
  /**
117
117
  * 返回只存在于其中一个数组的不同值。
118
118
  *
119
- * @param left - 决定左侧结果顺序的数组。
120
- * @param right - 决定右侧结果顺序的数组。
119
+ * @param left - 决定左侧结果顺序的数组
120
+ * @param right - 决定右侧结果顺序的数组
121
121
  * @returns 先按左侧、再按右侧首次出现顺序排列的对称差集;使用 SameValueZero 比较并忽略稀疏空位。
122
122
  */
123
123
  function symmetricDifference(left, right) {
@@ -130,7 +130,7 @@ function symmetricDifference(left, right) {
130
130
  /**
131
131
  * 判断选择器产生的键是否重复。
132
132
  *
133
- * @param items - 不会被修改的输入数组。
133
+ * @param items - 不会被修改的输入数组
134
134
  * @param selectKey - 返回比较键的函数;键使用 SameValueZero 语义比较。
135
135
  * @returns 存在至少一个重复键时返回 `true`。
136
136
  */
@@ -149,8 +149,8 @@ function hasDuplicatesBy(items, selectKey) {
149
149
  * 判断所有项目是否具有相同的选择器结果。
150
150
  *
151
151
  * @remarks 空数组、只有稀疏空位的数组和单项数组按数学惯例返回 `true`;空位不会调用选择器。
152
- * @param items - 不会被修改的输入数组。
153
- * @param selectKey - 返回比较键的函数。
152
+ * @param items - 不会被修改的输入数组
153
+ * @param selectKey - 返回比较键的函数
154
154
  * @returns 所有键都满足 SameValueZero 相等时返回 `true`。
155
155
  */
156
156
  function allEqualBy(items, selectKey) {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/array/index.ts"],"sourcesContent":["/** 从数组项中提取可比较键的函数。 */\nexport type KeySelector<Item, Key> = (item: Item, index: number) => Key;\n\n/**\n * 将只读数组按固定大小分组。\n *\n * @typeParam Item - 数组项类型。\n * @param items - 不会被修改的输入数组。\n * @param size - 每组最多包含的项目数,必须是正安全整数。\n * @returns 新建的二维数组;最后一组可能小于 `size`。\n * @throws `RangeError` 当 `size` 不是正安全整数。\n */\nexport function chunk<Item>(items: readonly Item[], size: number): Item[][] {\n\tif (!Number.isSafeInteger(size) || size <= 0) {\n\t\tthrow new RangeError(\"`size` 必须是正安全整数。\");\n\t}\n\n\tconst result: Item[][] = [];\n\tfor (let index = 0; index < items.length; index += size) {\n\t\tresult.push(items.slice(index, index + size));\n\t}\n\treturn result;\n}\n\n/**\n * 删除数组中的 `null` 与 `undefined`,保留 `false`、`0` 和空字符串。\n *\n * @param items - 可包含空值的只读数组。\n * @returns 保持原顺序的新数组。\n */\nexport function removeNullishValues<Item>(items: readonly (Item | null | undefined)[]): Item[] {\n\treturn items.filter((item): item is Item => item !== null && item !== undefined);\n}\n\n/**\n * 使用 JavaScript `Set` 的 SameValueZero 语义去重。\n *\n * @param items - 不会被修改的输入数组。\n * @returns 保留每个值首次出现顺序的新数组;稀疏数组空位被忽略。\n */\nexport function unique<Item>(items: readonly Item[]): Item[] {\n\tconst result: Item[] = [];\n\tconst seen = new Set<Item>();\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tif (!(index in items)) continue;\n\t\tconst item = items[index] as Item;\n\t\tif (seen.has(item)) continue;\n\t\tseen.add(item);\n\t\tresult.push(item);\n\t}\n\treturn result;\n}\n\n/**\n * 按选择器返回的键去重。\n *\n * @param items - 不会被修改的输入数组。\n * @param selectKey - 接收项目与索引并返回去重键的函数。\n * @returns 保留每个键首次出现项目的新数组;稀疏数组空位被忽略。\n */\nexport function uniqueBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): Item[] {\n\tconst seen = new Set<Key>();\n\tconst result: Item[] = [];\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tconst item = items[index];\n\t\tif (item === undefined && !(index in items)) continue;\n\t\tconst key = selectKey(item as Item, index);\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tresult.push(item as Item);\n\t}\n\treturn result;\n}\n\n/**\n * 按选择器结果分组。\n *\n * @param items - 不会被修改的输入数组。\n * @param selectKey - 返回任意 `Map` 键的函数。\n * @returns 按键首次出现顺序排列的 `Map`;每个分组保持输入顺序,稀疏空位被忽略。\n */\nexport function groupBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): Map<Key, Item[]> {\n\tconst groups = new Map<Key, Item[]>();\n\titems.forEach((item, index) => {\n\t\tconst key = selectKey(item, index);\n\t\tconst group = groups.get(key);\n\t\tif (group === undefined) groups.set(key, [item]);\n\t\telse group.push(item);\n\t});\n\treturn groups;\n}\n\n/**\n * 按谓词把数组拆分为匹配项和非匹配项。\n *\n * @param items - 不会被修改的输入数组。\n * @param predicate - 接收项目与索引的判断函数。\n * @returns 二元组:第一项匹配谓词,第二项不匹配;两组都保持原顺序并忽略稀疏空位。\n */\nexport function partition<Item>(items: readonly Item[], predicate: (item: Item, index: number) => boolean): [matched: Item[], unmatched: Item[]] {\n\tconst matched: Item[] = [];\n\tconst unmatched: Item[] = [];\n\titems.forEach((item, index) => (predicate(item, index) ? matched : unmatched).push(item));\n\treturn [matched, unmatched];\n}\n\n/**\n * 返回只出现在左侧数组中的不同值。\n *\n * @param left - 主输入数组。\n * @param right - 需要排除的值。\n * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。\n */\nexport function difference<Item>(left: readonly Item[], right: readonly Item[]): Item[] {\n\tconst excluded = new Set(unique(right));\n\treturn unique(left).filter((item) => !excluded.has(item));\n}\n\n/**\n * 返回两个数组共有的不同值。\n *\n * @param left - 决定结果顺序的数组。\n * @param right - 用于成员判断的数组。\n * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。\n */\nexport function intersection<Item>(left: readonly Item[], right: readonly Item[]): Item[] {\n\tconst included = new Set(unique(right));\n\treturn unique(left).filter((item) => included.has(item));\n}\n\n/**\n * 返回只存在于其中一个数组的不同值。\n *\n * @param left - 决定左侧结果顺序的数组。\n * @param right - 决定右侧结果顺序的数组。\n * @returns 先按左侧、再按右侧首次出现顺序排列的对称差集;使用 SameValueZero 比较并忽略稀疏空位。\n */\nexport function symmetricDifference<Item>(left: readonly Item[], right: readonly Item[]): Item[] {\n\tconst leftValues = unique(left);\n\tconst rightValues = unique(right);\n\tconst leftSet = new Set(leftValues);\n\tconst rightSet = new Set(rightValues);\n\treturn [...leftValues.filter((item) => !rightSet.has(item)), ...rightValues.filter((item) => !leftSet.has(item))];\n}\n\n/**\n * 判断选择器产生的键是否重复。\n *\n * @param items - 不会被修改的输入数组。\n * @param selectKey - 返回比较键的函数;键使用 SameValueZero 语义比较。\n * @returns 存在至少一个重复键时返回 `true`。\n */\nexport function hasDuplicatesBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): boolean {\n\tconst seen = new Set<Key>();\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tconst item = items[index];\n\t\tif (item === undefined && !(index in items)) continue;\n\t\tconst key = selectKey(item as Item, index);\n\t\tif (seen.has(key)) return true;\n\t\tseen.add(key);\n\t}\n\treturn false;\n}\n\n/**\n * 判断所有项目是否具有相同的选择器结果。\n *\n * @remarks 空数组、只有稀疏空位的数组和单项数组按数学惯例返回 `true`;空位不会调用选择器。\n * @param items - 不会被修改的输入数组。\n * @param selectKey - 返回比较键的函数。\n * @returns 所有键都满足 SameValueZero 相等时返回 `true`。\n */\nexport function allEqualBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): boolean {\n\tlet first: Key | undefined;\n\tlet hasFirst = false;\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tconst item = items[index];\n\t\tif (item === undefined && !(index in items)) continue;\n\t\tconst current = selectKey(item as Item, index);\n\t\tif (!hasFirst) {\n\t\t\tfirst = current;\n\t\t\thasFirst = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!(first === current || (Number.isNaN(first) && Number.isNaN(current)))) return false;\n\t}\n\treturn true;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/array/index.ts"],"sourcesContent":["/** 从数组项中提取可比较键的函数 */\nexport type KeySelector<Item, Key> = (item: Item, index: number) => Key;\n\n/**\n * 将只读数组按固定大小分组。\n *\n * @typeParam Item - 数组项类型\n * @param items - 不会被修改的输入数组\n * @param size - 每组最多包含的项目数,必须是正安全整数。\n * @returns 新建的二维数组;最后一组可能小于 `size`。\n * @throws `RangeError` 当 `size` 不是正安全整数。\n */\nexport function chunk<Item>(items: readonly Item[], size: number): Item[][] {\n\tif (!Number.isSafeInteger(size) || size <= 0) {\n\t\tthrow new RangeError(\"`size` must be a positive safe integer.\");\n\t}\n\n\tconst result: Item[][] = [];\n\tfor (let index = 0; index < items.length; index += size) {\n\t\tresult.push(items.slice(index, index + size));\n\t}\n\treturn result;\n}\n\n/**\n * 删除数组中的 `null` 与 `undefined`,保留 `false`、`0` 和空字符串。\n *\n * @param items - 可包含空值的只读数组\n * @returns 保持原顺序的新数组\n */\nexport function removeNullishValues<Item>(items: readonly (Item | null | undefined)[]): Item[] {\n\treturn items.filter((item): item is Item => item !== null && item !== undefined);\n}\n\n/**\n * 使用 JavaScript `Set` 的 SameValueZero 语义去重。\n *\n * @param items - 不会被修改的输入数组\n * @returns 保留每个值首次出现顺序的新数组;稀疏数组空位被忽略。\n */\nexport function unique<Item>(items: readonly Item[]): Item[] {\n\tconst result: Item[] = [];\n\tconst seen = new Set<Item>();\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tif (!(index in items)) continue;\n\t\tconst item = items[index] as Item;\n\t\tif (seen.has(item)) continue;\n\t\tseen.add(item);\n\t\tresult.push(item);\n\t}\n\treturn result;\n}\n\n/**\n * 按选择器返回的键去重。\n *\n * @param items - 不会被修改的输入数组\n * @param selectKey - 接收项目与索引并返回去重键的函数\n * @returns 保留每个键首次出现项目的新数组;稀疏数组空位被忽略。\n */\nexport function uniqueBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): Item[] {\n\tconst seen = new Set<Key>();\n\tconst result: Item[] = [];\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tconst item = items[index];\n\t\tif (item === undefined && !(index in items)) continue;\n\t\tconst key = selectKey(item as Item, index);\n\t\tif (seen.has(key)) continue;\n\t\tseen.add(key);\n\t\tresult.push(item as Item);\n\t}\n\treturn result;\n}\n\n/**\n * 按选择器结果分组。\n *\n * @param items - 不会被修改的输入数组\n * @param selectKey - 返回任意 `Map` 键的函数\n * @returns 按键首次出现顺序排列的 `Map`;每个分组保持输入顺序,稀疏空位被忽略。\n */\nexport function groupBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): Map<Key, Item[]> {\n\tconst groups = new Map<Key, Item[]>();\n\titems.forEach((item, index) => {\n\t\tconst key = selectKey(item, index);\n\t\tconst group = groups.get(key);\n\t\tif (group === undefined) groups.set(key, [item]);\n\t\telse group.push(item);\n\t});\n\treturn groups;\n}\n\n/**\n * 按谓词把数组拆分为匹配项和非匹配项。\n *\n * @param items - 不会被修改的输入数组\n * @param predicate - 接收项目与索引的判断函数\n * @returns 二元组:第一项匹配谓词,第二项不匹配;两组都保持原顺序并忽略稀疏空位。\n */\nexport function partition<Item>(items: readonly Item[], predicate: (item: Item, index: number) => boolean): [matched: Item[], unmatched: Item[]] {\n\tconst matched: Item[] = [];\n\tconst unmatched: Item[] = [];\n\titems.forEach((item, index) => (predicate(item, index) ? matched : unmatched).push(item));\n\treturn [matched, unmatched];\n}\n\n/**\n * 返回只出现在左侧数组中的不同值。\n *\n * @param left - 主输入数组\n * @param right - 需要排除的值\n * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。\n */\nexport function difference<Item>(left: readonly Item[], right: readonly Item[]): Item[] {\n\tconst excluded = new Set(unique(right));\n\treturn unique(left).filter((item) => !excluded.has(item));\n}\n\n/**\n * 返回两个数组共有的不同值。\n *\n * @param left - 决定结果顺序的数组\n * @param right - 用于成员判断的数组\n * @returns 保留左侧首次出现顺序的去重结果;两侧稀疏空位都被忽略。\n */\nexport function intersection<Item>(left: readonly Item[], right: readonly Item[]): Item[] {\n\tconst included = new Set(unique(right));\n\treturn unique(left).filter((item) => included.has(item));\n}\n\n/**\n * 返回只存在于其中一个数组的不同值。\n *\n * @param left - 决定左侧结果顺序的数组\n * @param right - 决定右侧结果顺序的数组\n * @returns 先按左侧、再按右侧首次出现顺序排列的对称差集;使用 SameValueZero 比较并忽略稀疏空位。\n */\nexport function symmetricDifference<Item>(left: readonly Item[], right: readonly Item[]): Item[] {\n\tconst leftValues = unique(left);\n\tconst rightValues = unique(right);\n\tconst leftSet = new Set(leftValues);\n\tconst rightSet = new Set(rightValues);\n\treturn [...leftValues.filter((item) => !rightSet.has(item)), ...rightValues.filter((item) => !leftSet.has(item))];\n}\n\n/**\n * 判断选择器产生的键是否重复。\n *\n * @param items - 不会被修改的输入数组\n * @param selectKey - 返回比较键的函数;键使用 SameValueZero 语义比较。\n * @returns 存在至少一个重复键时返回 `true`。\n */\nexport function hasDuplicatesBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): boolean {\n\tconst seen = new Set<Key>();\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tconst item = items[index];\n\t\tif (item === undefined && !(index in items)) continue;\n\t\tconst key = selectKey(item as Item, index);\n\t\tif (seen.has(key)) return true;\n\t\tseen.add(key);\n\t}\n\treturn false;\n}\n\n/**\n * 判断所有项目是否具有相同的选择器结果。\n *\n * @remarks 空数组、只有稀疏空位的数组和单项数组按数学惯例返回 `true`;空位不会调用选择器。\n * @param items - 不会被修改的输入数组\n * @param selectKey - 返回比较键的函数\n * @returns 所有键都满足 SameValueZero 相等时返回 `true`。\n */\nexport function allEqualBy<Item, Key>(items: readonly Item[], selectKey: KeySelector<Item, Key>): boolean {\n\tlet first: Key | undefined;\n\tlet hasFirst = false;\n\tfor (let index = 0; index < items.length; index += 1) {\n\t\tconst item = items[index];\n\t\tif (item === undefined && !(index in items)) continue;\n\t\tconst current = selectKey(item as Item, index);\n\t\tif (!hasFirst) {\n\t\t\tfirst = current;\n\t\t\thasFirst = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!(first === current || (Number.isNaN(first) && Number.isNaN(current)))) return false;\n\t}\n\treturn true;\n}\n"],"mappings":"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"}
@@ -4,10 +4,10 @@ const maximumTimerDelay = 2147483647;
4
4
  * 创建符合 Web Platform 约定的取消错误。
5
5
  *
6
6
  * @param signal - 已进入取消状态的信号;其 `reason` 会保存在错误的 `cause` 中。
7
- * @returns 名称为 `AbortError` 的新错误实例。
7
+ * @returns 名称为 `AbortError` 的新错误实例
8
8
  */
9
9
  const createAbortError = (signal) => {
10
- const error = new Error("操作已取消。", { cause: signal.reason });
10
+ const error = new Error("The operation was aborted.", { cause: signal.reason });
11
11
  error.name = "AbortError";
12
12
  return error;
13
13
  };
@@ -23,21 +23,21 @@ const throwIfAborted = (signal) => {
23
23
  /**
24
24
  * 校验宿主计时器可以稳定表示的延迟。
25
25
  *
26
- * @param milliseconds - 待校验的毫秒数。
27
- * @param name - 用于错误消息的参数名称。
26
+ * @param milliseconds - 待校验的毫秒数
27
+ * @param name - 用于错误消息的参数名称
28
28
  * @returns 原始延迟值,便于调用方在校验后直接使用。
29
29
  * @throws `RangeError` 当值非有限、为负数或超过 32 位计时器上限。
30
30
  */
31
31
  const assertDelay = (milliseconds, name = "milliseconds") => {
32
- if (!Number.isFinite(milliseconds) || milliseconds < 0 || milliseconds > maximumTimerDelay) throw new RangeError(`\`${name}\` 必须是 0 到 ${maximumTimerDelay} 之间的有限数。`);
32
+ if (!Number.isFinite(milliseconds) || milliseconds < 0 || milliseconds > maximumTimerDelay) throw new RangeError(`\`${name}\` must be a finite number between 0 and ${maximumTimerDelay}.`);
33
33
  return milliseconds;
34
34
  };
35
35
  /**
36
36
  * 等待指定时间,并支持 `AbortSignal`。
37
37
  *
38
- * @param milliseconds - 0 至 2,147,483,647 的有限毫秒数。
39
- * @param options - 可选取消信号。
40
- * @returns 到期后完成的 Promise。
38
+ * @param milliseconds - 0 至 2,147,483,647 的有限毫秒数
39
+ * @param options - 可选取消信号
40
+ * @returns 到期后完成的 Promise
41
41
  * @throws 参数非法时同步抛出 `RangeError`;信号已取消时同步抛出 `AbortError`。运行期间取消则拒绝返回的 Promise。
42
42
  */
43
43
  function sleep(milliseconds, options = {}) {
@@ -65,9 +65,9 @@ function sleep(milliseconds, options = {}) {
65
65
  * @remarks 超时或取消只停止等待,不能自动取消底层操作;需要真正取消时应同时把
66
66
  * 同一个 `AbortSignal` 传给底层 API。
67
67
  * @param promise - 需要等待的 Promise 或 PromiseLike。
68
- * @param timeoutMs - 0 至 2,147,483,647 的有限等待时间。
69
- * @param options - 取消信号与自定义消息。
70
- * @returns 底层 Promise 的结果。
68
+ * @param timeoutMs - 0 至 2,147,483,647 的有限等待时间
69
+ * @param options - 取消信号与自定义消息
70
+ * @returns 底层 Promise 的结果
71
71
  * @throws 等待时间非法或信号已取消时同步抛错;运行期间的超时、取消及源 Promise 失败通过返回的 Promise 拒绝。
72
72
  */
73
73
  function withTimeout(promise, timeoutMs, options = {}) {
@@ -85,7 +85,7 @@ function withTimeout(promise, timeoutMs, options = {}) {
85
85
  /**
86
86
  * 只允许 Promise、超时和取消三个竞争来源中的首个结果生效。
87
87
  *
88
- * @param action - 首个完成来源的结算动作。
88
+ * @param action - 首个完成来源的结算动作
89
89
  */
90
90
  function settle(action) {
91
91
  if (settled) return;
@@ -102,7 +102,7 @@ function withTimeout(promise, timeoutMs, options = {}) {
102
102
  }
103
103
  timer = setTimeout(() => {
104
104
  settle(() => {
105
- reject(new Error(options.message ?? `操作超过 ${delay} 毫秒仍未完成。`));
105
+ reject(new Error(options.message ?? `The operation timed out after ${delay} milliseconds.`));
106
106
  });
107
107
  }, delay);
108
108
  signal?.addEventListener("abort", onAbort, { once: true });
@@ -120,10 +120,10 @@ function withTimeout(promise, timeoutMs, options = {}) {
120
120
  /**
121
121
  * 使用有上限的指数退避重试操作。
122
122
  *
123
- * @typeParam Result - 操作结果类型。
123
+ * @typeParam Result - 操作结果类型
124
124
  * @param operation - 每次尝试都会调用的函数;`attempt` 从 1 开始。
125
- * @param options - 尝试次数、退避和取消策略。
126
- * @returns 首次成功结果。
125
+ * @param options - 尝试次数、退避和取消策略
126
+ * @returns 首次成功结果
127
127
  * @throws 最后一次操作错误、`shouldRetry` 错误或名称为 `AbortError` 的取消错误;策略参数非法时抛出 `RangeError`。
128
128
  */
129
129
  async function retry(operation, options = {}) {
@@ -131,8 +131,8 @@ async function retry(operation, options = {}) {
131
131
  const initialDelay = assertDelay(options.delayMs ?? 200, "delayMs");
132
132
  const maximumDelay = assertDelay(options.maxDelayMs ?? 3e4, "maxDelayMs");
133
133
  const factor = options.factor ?? 2;
134
- if (!Number.isSafeInteger(attempts) || attempts <= 0) throw new RangeError("`attempts` 必须是正安全整数。");
135
- if (!Number.isFinite(factor) || factor < 1) throw new RangeError("`factor` 必须是大于或等于 1 的有限数。");
134
+ if (!Number.isSafeInteger(attempts) || attempts <= 0) throw new RangeError("`attempts` must be a positive safe integer.");
135
+ if (!Number.isFinite(factor) || factor < 1) throw new RangeError("`factor` must be a finite number greater than or equal to 1.");
136
136
  for (let attempt = 1; attempt <= attempts; attempt += 1) {
137
137
  throwIfAborted(options.signal);
138
138
  const context = options.signal === void 0 ? { attempt } : {
@@ -146,22 +146,22 @@ async function retry(operation, options = {}) {
146
146
  await sleep(initialDelay === 0 ? 0 : Math.min(initialDelay * factor ** (attempt - 1), maximumDelay), options.signal === void 0 ? {} : { signal: options.signal });
147
147
  }
148
148
  }
149
- throw new Error("重试结束但未获得结果。");
149
+ throw new Error("Retry attempts ended without a result.");
150
150
  }
151
151
  /**
152
152
  * 以固定并发度映射数组,并保持结果顺序。
153
153
  *
154
154
  * @remarks 任一映射失败后不会再调度新项目,但已经开始的映射无法自动取消;映射器
155
155
  * 应使用传入的 `signal` 取消底层工作。
156
- * @param items - 不会被修改的输入数组。
156
+ * @param items - 不会被修改的输入数组
157
157
  * @param concurrency - 同时运行的最大任务数,必须为正安全整数。
158
- * @param mapper - 接收项目、索引和取消信号的映射函数。
159
- * @param options - 可选取消信号。
158
+ * @param mapper - 接收项目、索引和取消信号的映射函数
159
+ * @param options - 可选取消信号
160
160
  * @returns 与输入长度和顺序一致的结果数组;稀疏空位保持为空位且不会调用映射器。
161
161
  * @throws `RangeError` 当 `concurrency` 不是正安全整数;取消时抛出名称为 `AbortError` 的 `Error`。
162
162
  */
163
163
  async function mapConcurrent(items, concurrency, mapper, options = {}) {
164
- if (!Number.isSafeInteger(concurrency) || concurrency <= 0) throw new RangeError("`concurrency` 必须是正安全整数。");
164
+ if (!Number.isSafeInteger(concurrency) || concurrency <= 0) throw new RangeError("`concurrency` must be a positive safe integer.");
165
165
  throwIfAborted(options.signal);
166
166
  const results = new Array(items.length);
167
167
  let nextIndex = 0;
@@ -197,9 +197,9 @@ async function mapConcurrent(items, concurrency, mapper, options = {}) {
197
197
  *
198
198
  * @remarks 同一窗口内的所有调用都会等待最后一组参数对应的执行结果;回调错误会原样
199
199
  * 拒绝该批次的全部调用,不会留下永久 pending 的 Promise。
200
- * @param callback - 同步或异步回调。
200
+ * @param callback - 同步或异步回调
201
201
  * @param delayMs - 0 至 2,147,483,647 的有限等待时间,默认 300 毫秒。
202
- * @returns 具有取消、立即执行和状态方法的防抖函数。
202
+ * @returns 具有取消、立即执行和状态方法的防抖函数
203
203
  * @throws `RangeError` 当延迟不在平台计时器支持范围内。
204
204
  */
205
205
  function debounce(callback, delayMs = 300) {
@@ -210,12 +210,12 @@ function debounce(callback, delayMs = 300) {
210
210
  /**
211
211
  * 执行并结算当前防抖批次。
212
212
  *
213
- * @returns 最后一组参数对应的回调结果。
213
+ * @returns 最后一组参数对应的回调结果
214
214
  * @throws 没有待处理批次时抛出 `Error`;回调错误会原样传播给批次中的全部调用方。
215
215
  */
216
216
  const execute = async () => {
217
217
  const arguments_ = latestArguments;
218
- if (arguments_ === void 0) throw new Error("当前没有待处理的防抖调用。");
218
+ if (arguments_ === void 0) throw new Error("There is no pending debounced invocation.");
219
219
  latestArguments = void 0;
220
220
  timer = void 0;
221
221
  const currentWaiters = waiters;
@@ -237,7 +237,7 @@ function debounce(callback, delayMs = 300) {
237
237
  * 更新批次参数并返回当前调用方专属的等待 Promise。
238
238
  *
239
239
  * @param arguments_ - 本次调用参数;同批次中只有最后一组参数会执行。
240
- * @returns 与当前批次共享结果、但可独立结算的 Promise。
240
+ * @returns 与当前批次共享结果、但可独立结算的 Promise
241
241
  */
242
242
  const debounced = (...arguments_) => {
243
243
  latestArguments = arguments_;
@@ -256,7 +256,7 @@ function debounce(callback, delayMs = 300) {
256
256
  if (timer !== void 0) clearTimeout(timer);
257
257
  timer = void 0;
258
258
  latestArguments = void 0;
259
- const error = reason ?? /* @__PURE__ */ new Error("防抖调用已取消。");
259
+ const error = reason ?? /* @__PURE__ */ new Error("The debounced invocation was cancelled.");
260
260
  waiters.forEach((waiter) => {
261
261
  waiter.reject(error);
262
262
  });
@@ -275,9 +275,9 @@ function debounce(callback, delayMs = 300) {
275
275
  *
276
276
  * @remarks 窗口内的调用共享首次调用结果。若回调执行时间超过窗口,后续调用仍会等待
277
277
  * 当前回调,避免异步操作重入;该函数不安排尾缘调用。
278
- * @param callback - 同步或异步回调。
278
+ * @param callback - 同步或异步回调
279
279
  * @param delayMs - 0 至 2,147,483,647 的有限冷却时间,默认 300 毫秒。
280
- * @returns 具有取消和状态方法的前缘节流函数。
280
+ * @returns 具有取消和状态方法的前缘节流函数
281
281
  * @throws `RangeError` 当延迟不在平台计时器支持范围内。
282
282
  */
283
283
  function throttle(callback, delayMs = 300) {
@@ -298,7 +298,7 @@ function throttle(callback, delayMs = 300) {
298
298
  * 执行前缘调用或复用当前窗口的共享 Promise。
299
299
  *
300
300
  * @param arguments_ - 仅新窗口首个调用会使用的参数。
301
- * @returns 当前窗口首次调用的 Promise。
301
+ * @returns 当前窗口首次调用的 Promise
302
302
  */
303
303
  const throttled = (...arguments_) => {
304
304
  if (current !== void 0) return current;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../../src/async/index.ts"],"sourcesContent":["/** 统一同步返回值与 PromiseLike 返回值的内部回调签名。 */\ntype AsyncCallback<Arguments extends unknown[], Result> = (...arguments_: Arguments) => Result | PromiseLike<Result>;\n\n/** 记录同一防抖批次中每个调用方独立的 Promise 结算函数。 */\ninterface PromiseWaiter<Result> {\n\t/**\n\t * 使用批次失败原因拒绝当前调用方。\n\t * @param reason - `cancel` 提供的原因或共享回调抛出的原始错误。\n\t */\n\treject: (reason?: unknown) => void;\n\t/**\n\t * 使用共享回调结果完成当前调用方,并采用传入 PromiseLike 的最终状态。\n\t * @param value - 当前防抖批次唯一一次回调执行产生的共享结果。\n\t */\n\tresolve: (value: Result | PromiseLike<Result>) => void;\n}\n\n// 浏览器和 Node.js 的计时器普遍以有符号 32 位整数保存延迟;更大的值可能被\n// 静默截断为约 1 ms,因此公共 API 在进入平台计时器前统一拒绝它。\nconst maximumTimerDelay = 2_147_483_647;\n\n/** 可接收取消信号的通用选项。 */\nexport interface AbortOptions {\n\t/** 已取消时立即失败;运行期间取消时停止等待并拒绝 Promise。 */\n\tsignal?: AbortSignal;\n}\n\n/** {@link withTimeout} 的行为选项。 */\nexport interface TimeoutOptions extends AbortOptions {\n\t/** 超时时使用的开发者消息 */\n\tmessage?: string;\n}\n\n/** 每次重试操作接收的上下文。 */\nexport interface RetryContext {\n\t/** 从 1 开始的当前尝试次数。 */\n\tattempt: number;\n\t/** 调用方提供的取消信号。 */\n\tsignal?: AbortSignal;\n}\n\n/** {@link retry} 的策略选项。 */\nexport interface RetryOptions extends AbortOptions {\n\t/** 最大尝试次数,包含首次调用;默认 `3`。 */\n\tattempts?: number;\n\t/** 首次重试前的等待毫秒数,最大 2,147,483,647;默认 `200`。 */\n\tdelayMs?: number;\n\t/** 每次失败后的退避倍数,必须不小于 1;默认 `2`。 */\n\tfactor?: number;\n\t/** 单次等待上限,最大 2,147,483,647;默认 `30_000` 毫秒。 */\n\tmaxDelayMs?: number;\n\t/**\n\t * 决定当前失败后是否继续下一次尝试;默认重试所有尚未到达上限的错误。\n\t * @param error - 当前操作抛出或拒绝的原始值。\n\t * @param context - 当前尝试次数和调用方取消信号。\n\t * @returns `false` 时立即原样抛出当前错误;支持同步值或 PromiseLike。\n\t */\n\tshouldRetry?: (error: unknown, context: RetryContext) => boolean | PromiseLike<boolean>;\n}\n\n/** {@link mapConcurrent} 的执行选项。 */\nexport interface ConcurrentMapOptions {\n\t/** 已取消时停止调度新任务;已经开始的映射器需要自行响应同一信号。 */\n\tsignal?: AbortSignal;\n}\n\n/** Promise 感知的防抖函数。 */\nexport interface DebouncedFunction<Arguments extends unknown[], Result> {\n\t/**\n\t * 调度一次调用;同一等待窗口内的调用共享最后一组参数对应的结果。\n\t * @param arguments_ - 传给原始回调的参数;后续调用会覆盖尚未执行批次保存的参数。\n\t * @returns 当前批次的独立 Promise,最终与共享回调结果保持相同状态。\n\t */\n\t(...arguments_: Arguments): Promise<Result>;\n\t/**\n\t * 取消尚未执行的批次,并拒绝该批次的所有 Promise。\n\t * @param reason - 可选拒绝原因;省略时使用内部取消错误。\n\t */\n\tcancel: (reason?: unknown) => void;\n\t/**\n\t * 立即执行待处理批次,不创建第二次回调执行。\n\t * @returns 待处理批次的共享执行 Promise;没有批次时返回 `undefined`。\n\t */\n\tflush: () => Promise<Result> | undefined;\n\t/** @returns 当前存在尚未开始的批次时返回 `true`;正在执行但没有等待批次时返回 `false`。 */\n\tpending: () => boolean;\n}\n\n/** Promise 感知的前缘节流函数。 */\nexport interface ThrottledFunction<Arguments extends unknown[], Result> {\n\t/**\n\t * 在空闲时立即调用原始回调;执行期和冷却期内的调用共享首次调用的 Promise。\n\t * @param arguments_ - 仅窗口内首次调用的参数会传给原始回调。\n\t * @returns 当前执行窗口共享的 Promise。\n\t */\n\t(...arguments_: Arguments): Promise<Result>;\n\t/** 提前结束冷却期;已经开始的操作不会被取消,结束前仍禁止并发重入。 */\n\tcancel: () => void;\n\t/** @returns 原始回调正在执行或计时器仍处于冷却期时返回 `true`。 */\n\tpending: () => boolean;\n}\n\n/**\n * 创建符合 Web Platform 约定的取消错误。\n *\n * @param signal - 已进入取消状态的信号;其 `reason` 会保存在错误的 `cause` 中。\n * @returns 名称为 `AbortError` 的新错误实例。\n */\nconst createAbortError = (signal: AbortSignal): Error => {\n\tconst error = new Error(\"操作已取消。\", { cause: signal.reason });\n\terror.name = \"AbortError\";\n\treturn error;\n};\n\n/**\n * 在启动异步工作前同步拒绝已经取消的信号。\n *\n * @param signal - 可选取消信号;省略或尚未取消时不执行操作。\n * @throws `Error` 当信号已经取消,错误名称为 `AbortError`。\n */\nconst throwIfAborted = (signal: AbortSignal | undefined): void => {\n\tif (signal?.aborted) throw createAbortError(signal);\n};\n\n/**\n * 校验宿主计时器可以稳定表示的延迟。\n *\n * @param milliseconds - 待校验的毫秒数。\n * @param name - 用于错误消息的参数名称。\n * @returns 原始延迟值,便于调用方在校验后直接使用。\n * @throws `RangeError` 当值非有限、为负数或超过 32 位计时器上限。\n */\nconst assertDelay = (milliseconds: number, name = \"milliseconds\"): number => {\n\tif (!Number.isFinite(milliseconds) || milliseconds < 0 || milliseconds > maximumTimerDelay) {\n\t\tthrow new RangeError(`\\`${name}\\` 必须是 0 到 ${maximumTimerDelay} 之间的有限数。`);\n\t}\n\treturn milliseconds;\n};\n\n/**\n * 等待指定时间,并支持 `AbortSignal`。\n *\n * @param milliseconds - 0 至 2,147,483,647 的有限毫秒数。\n * @param options - 可选取消信号。\n * @returns 到期后完成的 Promise。\n * @throws 参数非法时同步抛出 `RangeError`;信号已取消时同步抛出 `AbortError`。运行期间取消则拒绝返回的 Promise。\n */\nexport function sleep(milliseconds: number, options: AbortOptions = {}): Promise<void> {\n\tconst delay = assertDelay(milliseconds);\n\tconst signal = options.signal;\n\tthrowIfAborted(signal);\n\n\treturn new Promise<void>((resolve, reject) => {\n\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t/** 取消计时器并使用标准取消错误拒绝等待。 */\n\t\tfunction onAbort() {\n\t\t\tif (signal === undefined) return;\n\t\t\tclearTimeout(timer);\n\t\t\treject(createAbortError(signal));\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}, delay);\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\n/**\n * 为 Promise 增加等待上限。\n *\n * @remarks 超时或取消只停止等待,不能自动取消底层操作;需要真正取消时应同时把\n * 同一个 `AbortSignal` 传给底层 API。\n * @param promise - 需要等待的 Promise 或 PromiseLike。\n * @param timeoutMs - 0 至 2,147,483,647 的有限等待时间。\n * @param options - 取消信号与自定义消息。\n * @returns 底层 Promise 的结果。\n * @throws 等待时间非法或信号已取消时同步抛错;运行期间的超时、取消及源 Promise 失败通过返回的 Promise 拒绝。\n */\nexport function withTimeout<Result>(promise: PromiseLike<Result>, timeoutMs: number, options: TimeoutOptions = {}): Promise<Result> {\n\tconst delay = assertDelay(timeoutMs, \"timeoutMs\");\n\tconst signal = options.signal;\n\tthrowIfAborted(signal);\n\n\treturn new Promise<Result>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t/** 清理竞争结束后不再需要的计时器和监听器。 */\n\t\tfunction cleanup() {\n\t\t\tclearTimeout(timer);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t}\n\t\t/**\n\t\t * 只允许 Promise、超时和取消三个竞争来源中的首个结果生效。\n\t\t *\n\t\t * @param action - 首个完成来源的结算动作。\n\t\t */\n\t\tfunction settle(action: () => void) {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\taction();\n\t\t}\n\t\t/** 使用调用方取消原因结束当前等待。 */\n\t\tfunction onAbort() {\n\t\t\tif (signal === undefined) return;\n\t\t\tsettle(() => {\n\t\t\t\treject(createAbortError(signal));\n\t\t\t});\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tsettle(() => {\n\t\t\t\treject(new Error(options.message ?? `操作超过 ${delay} 毫秒仍未完成。`));\n\t\t\t});\n\t\t}, delay);\n\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tPromise.resolve(promise).then(\n\t\t\t(value) => {\n\t\t\t\tsettle(() => {\n\t\t\t\t\tresolve(value);\n\t\t\t\t});\n\t\t\t},\n\t\t\t(error: unknown) => {\n\t\t\t\tsettle(() => {\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\t\t\t}\n\t\t);\n\t});\n}\n\n/**\n * 使用有上限的指数退避重试操作。\n *\n * @typeParam Result - 操作结果类型。\n * @param operation - 每次尝试都会调用的函数;`attempt` 从 1 开始。\n * @param options - 尝试次数、退避和取消策略。\n * @returns 首次成功结果。\n * @throws 最后一次操作错误、`shouldRetry` 错误或名称为 `AbortError` 的取消错误;策略参数非法时抛出 `RangeError`。\n */\nexport async function retry<Result>(\n\toperation: (context: RetryContext) => Result | PromiseLike<Result>,\n\toptions: RetryOptions = {}\n): Promise<Awaited<Result>> {\n\tconst attempts = options.attempts ?? 3;\n\tconst initialDelay = assertDelay(options.delayMs ?? 200, \"delayMs\");\n\tconst maximumDelay = assertDelay(options.maxDelayMs ?? 30_000, \"maxDelayMs\");\n\tconst factor = options.factor ?? 2;\n\tif (!Number.isSafeInteger(attempts) || attempts <= 0) throw new RangeError(\"`attempts` 必须是正安全整数。\");\n\tif (!Number.isFinite(factor) || factor < 1) throw new RangeError(\"`factor` 必须是大于或等于 1 的有限数。\");\n\n\tfor (let attempt = 1; attempt <= attempts; attempt += 1) {\n\t\tthrowIfAborted(options.signal);\n\t\tconst context: RetryContext = options.signal === undefined ? { attempt } : { attempt, signal: options.signal };\n\t\ttry {\n\t\t\treturn await operation(context);\n\t\t} catch (error) {\n\t\t\tif (attempt === attempts || (options.shouldRetry !== undefined && !(await options.shouldRetry(error, context)))) throw error;\n\t\t\t// `0 * Infinity` is `NaN`; a zero initial delay must remain zero even when\n\t\t\t// a very large factor overflows during a later attempt.\n\t\t\tconst delay = initialDelay === 0 ? 0 : Math.min(initialDelay * factor ** (attempt - 1), maximumDelay);\n\t\t\tawait sleep(delay, options.signal === undefined ? {} : { signal: options.signal });\n\t\t}\n\t}\n\n\tthrow new Error(\"重试结束但未获得结果。\");\n}\n\n/**\n * 以固定并发度映射数组,并保持结果顺序。\n *\n * @remarks 任一映射失败后不会再调度新项目,但已经开始的映射无法自动取消;映射器\n * 应使用传入的 `signal` 取消底层工作。\n * @param items - 不会被修改的输入数组。\n * @param concurrency - 同时运行的最大任务数,必须为正安全整数。\n * @param mapper - 接收项目、索引和取消信号的映射函数。\n * @param options - 可选取消信号。\n * @returns 与输入长度和顺序一致的结果数组;稀疏空位保持为空位且不会调用映射器。\n * @throws `RangeError` 当 `concurrency` 不是正安全整数;取消时抛出名称为 `AbortError` 的 `Error`。\n */\nexport async function mapConcurrent<Item, Result>(\n\titems: readonly Item[],\n\tconcurrency: number,\n\tmapper: (item: Item, index: number, signal: AbortSignal | undefined) => Result | PromiseLike<Result>,\n\toptions: ConcurrentMapOptions = {}\n): Promise<Awaited<Result>[]> {\n\tif (!Number.isSafeInteger(concurrency) || concurrency <= 0) {\n\t\tthrow new RangeError(\"`concurrency` 必须是正安全整数。\");\n\t}\n\tthrowIfAborted(options.signal);\n\n\tconst results = new Array<Awaited<Result>>(items.length);\n\tlet nextIndex = 0;\n\tlet failed = false;\n\t/**\n\t * 从共享游标持续领取映射任务。\n\t *\n\t * @remarks JavaScript 单线程执行保证“读取索引并递增”不会被另一个 Worker 插入,因此每个索引只会领取一次。\n\t * @returns 当前 Worker 没有剩余任务时完成。\n\t * @throws 原样传播取消错误或 Mapper 错误,并阻止其他 Worker 领取新任务。\n\t */\n\tconst worker = async () => {\n\t\twhile (!failed) {\n\t\t\tthrowIfAborted(options.signal);\n\t\t\tconst index = nextIndex;\n\t\t\tif (index >= items.length) return;\n\t\t\tnextIndex += 1;\n\t\t\tif (!(index in items)) continue;\n\t\t\ttry {\n\t\t\t\tresults[index] = await mapper(items[index] as Item, index, options.signal);\n\t\t\t} catch (error) {\n\t\t\t\tfailed = true;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t};\n\n\tconst workerCount = Math.min(concurrency, items.length);\n\tawait Promise.all(Array.from({ length: workerCount }, worker));\n\treturn results;\n}\n\n/**\n * 创建 Promise 感知的防抖函数。\n *\n * @remarks 同一窗口内的所有调用都会等待最后一组参数对应的执行结果;回调错误会原样\n * 拒绝该批次的全部调用,不会留下永久 pending 的 Promise。\n * @param callback - 同步或异步回调。\n * @param delayMs - 0 至 2,147,483,647 的有限等待时间,默认 300 毫秒。\n * @returns 具有取消、立即执行和状态方法的防抖函数。\n * @throws `RangeError` 当延迟不在平台计时器支持范围内。\n */\nexport function debounce<Arguments extends unknown[], Result>(\n\tcallback: AsyncCallback<Arguments, Result>,\n\tdelayMs = 300\n): DebouncedFunction<Arguments, Awaited<Result>> {\n\tconst delay = assertDelay(delayMs, \"delayMs\");\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet latestArguments: Arguments | undefined;\n\tlet waiters: PromiseWaiter<Awaited<Result>>[] = [];\n\n\t/**\n\t * 执行并结算当前防抖批次。\n\t *\n\t * @returns 最后一组参数对应的回调结果。\n\t * @throws 没有待处理批次时抛出 `Error`;回调错误会原样传播给批次中的全部调用方。\n\t */\n\tconst execute = async (): Promise<Awaited<Result>> => {\n\t\tconst arguments_ = latestArguments;\n\t\tif (arguments_ === undefined) {\n\t\t\tthrow new Error(\"当前没有待处理的防抖调用。\");\n\t\t}\n\t\tlatestArguments = undefined;\n\t\ttimer = undefined;\n\t\tconst currentWaiters = waiters;\n\t\twaiters = [];\n\t\ttry {\n\t\t\tconst result = await callback(...arguments_);\n\t\t\tcurrentWaiters.forEach((waiter) => {\n\t\t\t\twaiter.resolve(result);\n\t\t\t});\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tcurrentWaiters.forEach((waiter) => {\n\t\t\t\twaiter.reject(error);\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\t/**\n\t * 更新批次参数并返回当前调用方专属的等待 Promise。\n\t *\n\t * @param arguments_ - 本次调用参数;同批次中只有最后一组参数会执行。\n\t * @returns 与当前批次共享结果、但可独立结算的 Promise。\n\t */\n\tconst debounced = (...arguments_: Arguments) => {\n\t\tlatestArguments = arguments_;\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\ttimer = setTimeout(() => {\n\t\t\texecute().catch(() => undefined);\n\t\t}, delay);\n\t\treturn new Promise<Awaited<Result>>((resolve, reject) => {\n\t\t\twaiters.push({ reject, resolve });\n\t\t});\n\t};\n\n\tdebounced.cancel = (reason?: unknown) => {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\ttimer = undefined;\n\t\tlatestArguments = undefined;\n\t\tconst error = reason ?? new Error(\"防抖调用已取消。\");\n\t\twaiters.forEach((waiter) => {\n\t\t\twaiter.reject(error);\n\t\t});\n\t\twaiters = [];\n\t};\n\tdebounced.flush = () => {\n\t\tif (timer === undefined) return undefined;\n\t\tclearTimeout(timer);\n\t\treturn execute();\n\t};\n\tdebounced.pending = () => timer !== undefined;\n\treturn debounced;\n}\n\n/**\n * 创建 Promise 感知的前缘节流函数。\n *\n * @remarks 窗口内的调用共享首次调用结果。若回调执行时间超过窗口,后续调用仍会等待\n * 当前回调,避免异步操作重入;该函数不安排尾缘调用。\n * @param callback - 同步或异步回调。\n * @param delayMs - 0 至 2,147,483,647 的有限冷却时间,默认 300 毫秒。\n * @returns 具有取消和状态方法的前缘节流函数。\n * @throws `RangeError` 当延迟不在平台计时器支持范围内。\n */\nexport function throttle<Arguments extends unknown[], Result>(\n\tcallback: AsyncCallback<Arguments, Result>,\n\tdelayMs = 300\n): ThrottledFunction<Arguments, Awaited<Result>> {\n\tconst delay = assertDelay(delayMs, \"delayMs\");\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet current: Promise<Awaited<Result>> | undefined;\n\tlet cooling = false;\n\tlet settled = false;\n\n\t/**\n\t * 尝试释放当前节流窗口。\n\t *\n\t * @remarks 只有回调和冷却计时器都结束后才清空共享 Promise,避免长回调发生重入。\n\t */\n\tconst release = () => {\n\t\tif (!cooling && settled) current = undefined;\n\t};\n\t/**\n\t * 执行前缘调用或复用当前窗口的共享 Promise。\n\t *\n\t * @param arguments_ - 仅新窗口首个调用会使用的参数。\n\t * @returns 当前窗口首次调用的 Promise。\n\t */\n\tconst throttled = (...arguments_: Arguments) => {\n\t\tif (current !== undefined) return current;\n\t\tcooling = true;\n\t\tsettled = false;\n\t\tlet invocation: Promise<Awaited<Result>>;\n\t\ttry {\n\t\t\tinvocation = Promise.resolve(callback(...arguments_));\n\t\t} catch (error) {\n\t\t\tinvocation = Promise.reject(error);\n\t\t}\n\t\tcurrent = invocation;\n\t\tinvocation.then(\n\t\t\t() => {\n\t\t\t\tsettled = true;\n\t\t\t\trelease();\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tsettled = true;\n\t\t\t\trelease();\n\t\t\t}\n\t\t);\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = undefined;\n\t\t\tcooling = false;\n\t\t\trelease();\n\t\t}, delay);\n\t\treturn invocation;\n\t};\n\n\tthrottled.cancel = () => {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\ttimer = undefined;\n\t\tcooling = false;\n\t\trelease();\n\t};\n\tthrottled.pending = () => current !== undefined;\n\treturn throttled;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/async/index.ts"],"sourcesContent":["/** 统一同步返回值与 PromiseLike 返回值的内部回调签名。 */\ntype AsyncCallback<Arguments extends unknown[], Result> = (...arguments_: Arguments) => Result | PromiseLike<Result>;\n\n/** 记录同一防抖批次中每个调用方独立的 Promise 结算函数 */\ninterface PromiseWaiter<Result> {\n\t/**\n\t * 使用批次失败原因拒绝当前调用方。\n\t * @param reason - `cancel` 提供的原因或共享回调抛出的原始错误。\n\t */\n\treject: (reason?: unknown) => void;\n\t/**\n\t * 使用共享回调结果完成当前调用方,并采用传入 PromiseLike 的最终状态。\n\t * @param value - 当前防抖批次唯一一次回调执行产生的共享结果。\n\t */\n\tresolve: (value: Result | PromiseLike<Result>) => void;\n}\n\n// 浏览器和 Node.js 的计时器普遍以有符号 32 位整数保存延迟;更大的值可能被\n// 静默截断为约 1 ms,因此公共 API 在进入平台计时器前统一拒绝它。\nconst maximumTimerDelay = 2_147_483_647;\n\n/** 可接收取消信号的通用选项 */\nexport interface AbortOptions {\n\t/** 已取消时立即失败;运行期间取消时停止等待并拒绝 Promise。 */\n\tsignal?: AbortSignal;\n}\n\n/** {@link withTimeout} 的行为选项 */\nexport interface TimeoutOptions extends AbortOptions {\n\t/** 超时时使用的开发者消息 */\n\tmessage?: string;\n}\n\n/** 每次重试操作接收的上下文 */\nexport interface RetryContext {\n\t/** 从 1 开始的当前尝试次数 */\n\tattempt: number;\n\t/** 调用方提供的取消信号 */\n\tsignal?: AbortSignal;\n}\n\n/** {@link retry} 的策略选项 */\nexport interface RetryOptions extends AbortOptions {\n\t/** 最大尝试次数,包含首次调用;默认 `3`。 */\n\tattempts?: number;\n\t/** 首次重试前的等待毫秒数,最大 2,147,483,647;默认 `200`。 */\n\tdelayMs?: number;\n\t/** 每次失败后的退避倍数,必须不小于 1;默认 `2`。 */\n\tfactor?: number;\n\t/** 单次等待上限,最大 2,147,483,647;默认 `30_000` 毫秒。 */\n\tmaxDelayMs?: number;\n\t/**\n\t * 决定当前失败后是否继续下一次尝试;默认重试所有尚未到达上限的错误。\n\t * @param error - 当前操作抛出或拒绝的原始值\n\t * @param context - 当前尝试次数和调用方取消信号\n\t * @returns `false` 时立即原样抛出当前错误;支持同步值或 PromiseLike。\n\t */\n\tshouldRetry?: (error: unknown, context: RetryContext) => boolean | PromiseLike<boolean>;\n}\n\n/** {@link mapConcurrent} 的执行选项 */\nexport interface ConcurrentMapOptions {\n\t/** 已取消时停止调度新任务;已经开始的映射器需要自行响应同一信号。 */\n\tsignal?: AbortSignal;\n}\n\n/** Promise 感知的防抖函数 */\nexport interface DebouncedFunction<Arguments extends unknown[], Result> {\n\t/**\n\t * 调度一次调用;同一等待窗口内的调用共享最后一组参数对应的结果。\n\t * @param arguments_ - 传给原始回调的参数;后续调用会覆盖尚未执行批次保存的参数。\n\t * @returns 当前批次的独立 Promise,最终与共享回调结果保持相同状态。\n\t */\n\t(...arguments_: Arguments): Promise<Result>;\n\t/**\n\t * 取消尚未执行的批次,并拒绝该批次的所有 Promise。\n\t * @param reason - 可选拒绝原因;省略时使用内部取消错误。\n\t */\n\tcancel: (reason?: unknown) => void;\n\t/**\n\t * 立即执行待处理批次,不创建第二次回调执行。\n\t * @returns 待处理批次的共享执行 Promise;没有批次时返回 `undefined`。\n\t */\n\tflush: () => Promise<Result> | undefined;\n\t/** @returns 当前存在尚未开始的批次时返回 `true`;正在执行但没有等待批次时返回 `false`。 */\n\tpending: () => boolean;\n}\n\n/** Promise 感知的前缘节流函数 */\nexport interface ThrottledFunction<Arguments extends unknown[], Result> {\n\t/**\n\t * 在空闲时立即调用原始回调;执行期和冷却期内的调用共享首次调用的 Promise。\n\t * @param arguments_ - 仅窗口内首次调用的参数会传给原始回调。\n\t * @returns 当前执行窗口共享的 Promise\n\t */\n\t(...arguments_: Arguments): Promise<Result>;\n\t/** 提前结束冷却期;已经开始的操作不会被取消,结束前仍禁止并发重入。 */\n\tcancel: () => void;\n\t/** @returns 原始回调正在执行或计时器仍处于冷却期时返回 `true`。 */\n\tpending: () => boolean;\n}\n\n/**\n * 创建符合 Web Platform 约定的取消错误。\n *\n * @param signal - 已进入取消状态的信号;其 `reason` 会保存在错误的 `cause` 中。\n * @returns 名称为 `AbortError` 的新错误实例\n */\nconst createAbortError = (signal: AbortSignal): Error => {\n\tconst error = new Error(\"The operation was aborted.\", { cause: signal.reason });\n\terror.name = \"AbortError\";\n\treturn error;\n};\n\n/**\n * 在启动异步工作前同步拒绝已经取消的信号。\n *\n * @param signal - 可选取消信号;省略或尚未取消时不执行操作。\n * @throws `Error` 当信号已经取消,错误名称为 `AbortError`。\n */\nconst throwIfAborted = (signal: AbortSignal | undefined): void => {\n\tif (signal?.aborted) throw createAbortError(signal);\n};\n\n/**\n * 校验宿主计时器可以稳定表示的延迟。\n *\n * @param milliseconds - 待校验的毫秒数\n * @param name - 用于错误消息的参数名称\n * @returns 原始延迟值,便于调用方在校验后直接使用。\n * @throws `RangeError` 当值非有限、为负数或超过 32 位计时器上限。\n */\nconst assertDelay = (milliseconds: number, name = \"milliseconds\"): number => {\n\tif (!Number.isFinite(milliseconds) || milliseconds < 0 || milliseconds > maximumTimerDelay) {\n\t\tthrow new RangeError(`\\`${name}\\` must be a finite number between 0 and ${maximumTimerDelay}.`);\n\t}\n\treturn milliseconds;\n};\n\n/**\n * 等待指定时间,并支持 `AbortSignal`。\n *\n * @param milliseconds - 0 至 2,147,483,647 的有限毫秒数\n * @param options - 可选取消信号\n * @returns 到期后完成的 Promise\n * @throws 参数非法时同步抛出 `RangeError`;信号已取消时同步抛出 `AbortError`。运行期间取消则拒绝返回的 Promise。\n */\nexport function sleep(milliseconds: number, options: AbortOptions = {}): Promise<void> {\n\tconst delay = assertDelay(milliseconds);\n\tconst signal = options.signal;\n\tthrowIfAborted(signal);\n\n\treturn new Promise<void>((resolve, reject) => {\n\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t/** 取消计时器并使用标准取消错误拒绝等待。 */\n\t\tfunction onAbort() {\n\t\t\tif (signal === undefined) return;\n\t\t\tclearTimeout(timer);\n\t\t\treject(createAbortError(signal));\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t\tresolve();\n\t\t}, delay);\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t});\n}\n\n/**\n * 为 Promise 增加等待上限。\n *\n * @remarks 超时或取消只停止等待,不能自动取消底层操作;需要真正取消时应同时把\n * 同一个 `AbortSignal` 传给底层 API。\n * @param promise - 需要等待的 Promise 或 PromiseLike。\n * @param timeoutMs - 0 至 2,147,483,647 的有限等待时间\n * @param options - 取消信号与自定义消息\n * @returns 底层 Promise 的结果\n * @throws 等待时间非法或信号已取消时同步抛错;运行期间的超时、取消及源 Promise 失败通过返回的 Promise 拒绝。\n */\nexport function withTimeout<Result>(promise: PromiseLike<Result>, timeoutMs: number, options: TimeoutOptions = {}): Promise<Result> {\n\tconst delay = assertDelay(timeoutMs, \"timeoutMs\");\n\tconst signal = options.signal;\n\tthrowIfAborted(signal);\n\n\treturn new Promise<Result>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet timer: ReturnType<typeof setTimeout>;\n\t\t/** 清理竞争结束后不再需要的计时器和监听器。 */\n\t\tfunction cleanup() {\n\t\t\tclearTimeout(timer);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t}\n\t\t/**\n\t\t * 只允许 Promise、超时和取消三个竞争来源中的首个结果生效。\n\t\t *\n\t\t * @param action - 首个完成来源的结算动作\n\t\t */\n\t\tfunction settle(action: () => void) {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\taction();\n\t\t}\n\t\t/** 使用调用方取消原因结束当前等待。 */\n\t\tfunction onAbort() {\n\t\t\tif (signal === undefined) return;\n\t\t\tsettle(() => {\n\t\t\t\treject(createAbortError(signal));\n\t\t\t});\n\t\t}\n\t\ttimer = setTimeout(() => {\n\t\t\tsettle(() => {\n\t\t\t\treject(new Error(options.message ?? `The operation timed out after ${delay} milliseconds.`));\n\t\t\t});\n\t\t}, delay);\n\n\t\tsignal?.addEventListener(\"abort\", onAbort, { once: true });\n\t\tPromise.resolve(promise).then(\n\t\t\t(value) => {\n\t\t\t\tsettle(() => {\n\t\t\t\t\tresolve(value);\n\t\t\t\t});\n\t\t\t},\n\t\t\t(error: unknown) => {\n\t\t\t\tsettle(() => {\n\t\t\t\t\treject(error);\n\t\t\t\t});\n\t\t\t}\n\t\t);\n\t});\n}\n\n/**\n * 使用有上限的指数退避重试操作。\n *\n * @typeParam Result - 操作结果类型\n * @param operation - 每次尝试都会调用的函数;`attempt` 从 1 开始。\n * @param options - 尝试次数、退避和取消策略\n * @returns 首次成功结果\n * @throws 最后一次操作错误、`shouldRetry` 错误或名称为 `AbortError` 的取消错误;策略参数非法时抛出 `RangeError`。\n */\nexport async function retry<Result>(\n\toperation: (context: RetryContext) => Result | PromiseLike<Result>,\n\toptions: RetryOptions = {}\n): Promise<Awaited<Result>> {\n\tconst attempts = options.attempts ?? 3;\n\tconst initialDelay = assertDelay(options.delayMs ?? 200, \"delayMs\");\n\tconst maximumDelay = assertDelay(options.maxDelayMs ?? 30_000, \"maxDelayMs\");\n\tconst factor = options.factor ?? 2;\n\tif (!Number.isSafeInteger(attempts) || attempts <= 0) throw new RangeError(\"`attempts` must be a positive safe integer.\");\n\tif (!Number.isFinite(factor) || factor < 1) throw new RangeError(\"`factor` must be a finite number greater than or equal to 1.\");\n\n\tfor (let attempt = 1; attempt <= attempts; attempt += 1) {\n\t\tthrowIfAborted(options.signal);\n\t\tconst context: RetryContext = options.signal === undefined ? { attempt } : { attempt, signal: options.signal };\n\t\ttry {\n\t\t\treturn await operation(context);\n\t\t} catch (error) {\n\t\t\tif (attempt === attempts || (options.shouldRetry !== undefined && !(await options.shouldRetry(error, context)))) throw error;\n\t\t\t// `0 * Infinity` is `NaN`; a zero initial delay must remain zero even when\n\t\t\t// a very large factor overflows during a later attempt.\n\t\t\tconst delay = initialDelay === 0 ? 0 : Math.min(initialDelay * factor ** (attempt - 1), maximumDelay);\n\t\t\tawait sleep(delay, options.signal === undefined ? {} : { signal: options.signal });\n\t\t}\n\t}\n\n\tthrow new Error(\"Retry attempts ended without a result.\");\n}\n\n/**\n * 以固定并发度映射数组,并保持结果顺序。\n *\n * @remarks 任一映射失败后不会再调度新项目,但已经开始的映射无法自动取消;映射器\n * 应使用传入的 `signal` 取消底层工作。\n * @param items - 不会被修改的输入数组\n * @param concurrency - 同时运行的最大任务数,必须为正安全整数。\n * @param mapper - 接收项目、索引和取消信号的映射函数\n * @param options - 可选取消信号\n * @returns 与输入长度和顺序一致的结果数组;稀疏空位保持为空位且不会调用映射器。\n * @throws `RangeError` 当 `concurrency` 不是正安全整数;取消时抛出名称为 `AbortError` 的 `Error`。\n */\nexport async function mapConcurrent<Item, Result>(\n\titems: readonly Item[],\n\tconcurrency: number,\n\tmapper: (item: Item, index: number, signal: AbortSignal | undefined) => Result | PromiseLike<Result>,\n\toptions: ConcurrentMapOptions = {}\n): Promise<Awaited<Result>[]> {\n\tif (!Number.isSafeInteger(concurrency) || concurrency <= 0) {\n\t\tthrow new RangeError(\"`concurrency` must be a positive safe integer.\");\n\t}\n\tthrowIfAborted(options.signal);\n\n\tconst results = new Array<Awaited<Result>>(items.length);\n\tlet nextIndex = 0;\n\tlet failed = false;\n\t/**\n\t * 从共享游标持续领取映射任务。\n\t *\n\t * @remarks JavaScript 单线程执行保证“读取索引并递增”不会被另一个 Worker 插入,因此每个索引只会领取一次。\n\t * @returns 当前 Worker 没有剩余任务时完成。\n\t * @throws 原样传播取消错误或 Mapper 错误,并阻止其他 Worker 领取新任务。\n\t */\n\tconst worker = async () => {\n\t\twhile (!failed) {\n\t\t\tthrowIfAborted(options.signal);\n\t\t\tconst index = nextIndex;\n\t\t\tif (index >= items.length) return;\n\t\t\tnextIndex += 1;\n\t\t\tif (!(index in items)) continue;\n\t\t\ttry {\n\t\t\t\tresults[index] = await mapper(items[index] as Item, index, options.signal);\n\t\t\t} catch (error) {\n\t\t\t\tfailed = true;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t};\n\n\tconst workerCount = Math.min(concurrency, items.length);\n\tawait Promise.all(Array.from({ length: workerCount }, worker));\n\treturn results;\n}\n\n/**\n * 创建 Promise 感知的防抖函数。\n *\n * @remarks 同一窗口内的所有调用都会等待最后一组参数对应的执行结果;回调错误会原样\n * 拒绝该批次的全部调用,不会留下永久 pending 的 Promise。\n * @param callback - 同步或异步回调\n * @param delayMs - 0 至 2,147,483,647 的有限等待时间,默认 300 毫秒。\n * @returns 具有取消、立即执行和状态方法的防抖函数\n * @throws `RangeError` 当延迟不在平台计时器支持范围内。\n */\nexport function debounce<Arguments extends unknown[], Result>(\n\tcallback: AsyncCallback<Arguments, Result>,\n\tdelayMs = 300\n): DebouncedFunction<Arguments, Awaited<Result>> {\n\tconst delay = assertDelay(delayMs, \"delayMs\");\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet latestArguments: Arguments | undefined;\n\tlet waiters: PromiseWaiter<Awaited<Result>>[] = [];\n\n\t/**\n\t * 执行并结算当前防抖批次。\n\t *\n\t * @returns 最后一组参数对应的回调结果\n\t * @throws 没有待处理批次时抛出 `Error`;回调错误会原样传播给批次中的全部调用方。\n\t */\n\tconst execute = async (): Promise<Awaited<Result>> => {\n\t\tconst arguments_ = latestArguments;\n\t\tif (arguments_ === undefined) {\n\t\t\tthrow new Error(\"There is no pending debounced invocation.\");\n\t\t}\n\t\tlatestArguments = undefined;\n\t\ttimer = undefined;\n\t\tconst currentWaiters = waiters;\n\t\twaiters = [];\n\t\ttry {\n\t\t\tconst result = await callback(...arguments_);\n\t\t\tcurrentWaiters.forEach((waiter) => {\n\t\t\t\twaiter.resolve(result);\n\t\t\t});\n\t\t\treturn result;\n\t\t} catch (error) {\n\t\t\tcurrentWaiters.forEach((waiter) => {\n\t\t\t\twaiter.reject(error);\n\t\t\t});\n\t\t\tthrow error;\n\t\t}\n\t};\n\n\t/**\n\t * 更新批次参数并返回当前调用方专属的等待 Promise。\n\t *\n\t * @param arguments_ - 本次调用参数;同批次中只有最后一组参数会执行。\n\t * @returns 与当前批次共享结果、但可独立结算的 Promise\n\t */\n\tconst debounced = (...arguments_: Arguments) => {\n\t\tlatestArguments = arguments_;\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\ttimer = setTimeout(() => {\n\t\t\texecute().catch(() => undefined);\n\t\t}, delay);\n\t\treturn new Promise<Awaited<Result>>((resolve, reject) => {\n\t\t\twaiters.push({ reject, resolve });\n\t\t});\n\t};\n\n\tdebounced.cancel = (reason?: unknown) => {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\ttimer = undefined;\n\t\tlatestArguments = undefined;\n\t\tconst error = reason ?? new Error(\"The debounced invocation was cancelled.\");\n\t\twaiters.forEach((waiter) => {\n\t\t\twaiter.reject(error);\n\t\t});\n\t\twaiters = [];\n\t};\n\tdebounced.flush = () => {\n\t\tif (timer === undefined) return undefined;\n\t\tclearTimeout(timer);\n\t\treturn execute();\n\t};\n\tdebounced.pending = () => timer !== undefined;\n\treturn debounced;\n}\n\n/**\n * 创建 Promise 感知的前缘节流函数。\n *\n * @remarks 窗口内的调用共享首次调用结果。若回调执行时间超过窗口,后续调用仍会等待\n * 当前回调,避免异步操作重入;该函数不安排尾缘调用。\n * @param callback - 同步或异步回调\n * @param delayMs - 0 至 2,147,483,647 的有限冷却时间,默认 300 毫秒。\n * @returns 具有取消和状态方法的前缘节流函数\n * @throws `RangeError` 当延迟不在平台计时器支持范围内。\n */\nexport function throttle<Arguments extends unknown[], Result>(\n\tcallback: AsyncCallback<Arguments, Result>,\n\tdelayMs = 300\n): ThrottledFunction<Arguments, Awaited<Result>> {\n\tconst delay = assertDelay(delayMs, \"delayMs\");\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\tlet current: Promise<Awaited<Result>> | undefined;\n\tlet cooling = false;\n\tlet settled = false;\n\n\t/**\n\t * 尝试释放当前节流窗口。\n\t *\n\t * @remarks 只有回调和冷却计时器都结束后才清空共享 Promise,避免长回调发生重入。\n\t */\n\tconst release = () => {\n\t\tif (!cooling && settled) current = undefined;\n\t};\n\t/**\n\t * 执行前缘调用或复用当前窗口的共享 Promise。\n\t *\n\t * @param arguments_ - 仅新窗口首个调用会使用的参数。\n\t * @returns 当前窗口首次调用的 Promise\n\t */\n\tconst throttled = (...arguments_: Arguments) => {\n\t\tif (current !== undefined) return current;\n\t\tcooling = true;\n\t\tsettled = false;\n\t\tlet invocation: Promise<Awaited<Result>>;\n\t\ttry {\n\t\t\tinvocation = Promise.resolve(callback(...arguments_));\n\t\t} catch (error) {\n\t\t\tinvocation = Promise.reject(error);\n\t\t}\n\t\tcurrent = invocation;\n\t\tinvocation.then(\n\t\t\t() => {\n\t\t\t\tsettled = true;\n\t\t\t\trelease();\n\t\t\t},\n\t\t\t() => {\n\t\t\t\tsettled = true;\n\t\t\t\trelease();\n\t\t\t}\n\t\t);\n\t\ttimer = setTimeout(() => {\n\t\t\ttimer = undefined;\n\t\t\tcooling = false;\n\t\t\trelease();\n\t\t}, delay);\n\t\treturn invocation;\n\t};\n\n\tthrottled.cancel = () => {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\ttimer = undefined;\n\t\tcooling = false;\n\t\trelease();\n\t};\n\tthrottled.pending = () => current !== undefined;\n\treturn throttled;\n}\n"],"mappings":"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"}