foreslash 0.2.3 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Change Log
2
2
 
3
+ ## Version 0.2.4 - 2025-0
4
+
5
+ Unstable version
6
+
7
+ - Feat 🥥 Functions added: `retry` `parallel`
8
+ - Other fixes and improvements
9
+
10
+ 不稳定版本
11
+
12
+ - 功能 🥥 添加函数: `retry` `parallel`
13
+ - 其他修复与优化
14
+
3
15
  ## Version 0.2.3 - 2025-03-28
4
16
 
5
17
  Unstable version
package/lib/index.cmn.cjs CHANGED
@@ -351,12 +351,100 @@ function defer(asyncFunction, options) {
351
351
  });
352
352
  }
353
353
 
354
+ function clamp(num, min, max, options) {
355
+ var _a, _b;
356
+ if (isNaN(min))
357
+ throw new Error('Invalid min parameter');
358
+ if (isNaN(max))
359
+ throw new Error('Invalid max parameter');
360
+ if (max < min) {
361
+ [min, max] = [max, min];
362
+ }
363
+ const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
364
+ const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
365
+ const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
366
+ if (isNaN(num))
367
+ return defaultMin;
368
+ return num < min ? defaultMin : num > max ? defaultMax : num;
369
+ }
370
+
371
+ function parallel(args, fn, options) {
372
+ return __awaiter(this, void 0, void 0, function* () {
373
+ if (!args.length)
374
+ return [];
375
+ const { limit: _limit = 5 } = options || {};
376
+ const limit = clamp(Math.floor(_limit), 1, 100);
377
+ let current = 0;
378
+ const results = [];
379
+ const errors = [];
380
+ const asyncFn = tryit(fn);
381
+ const processor = () => __awaiter(this, void 0, void 0, function* () {
382
+ while (current < args.length) {
383
+ const index = current++;
384
+ const [err, result] = yield asyncFn(args[index]);
385
+ if (err)
386
+ errors.push({ index, error: err });
387
+ else
388
+ results[index] = result;
389
+ }
390
+ });
391
+ const tasks = [];
392
+ for (let i = 0; i < Math.min(args.length, limit); i++) {
393
+ tasks.push(processor());
394
+ }
395
+ yield Promise.all(tasks);
396
+ if (errors.length) {
397
+ throw new Error(`Parallel execution failed on index: ${errors.map((e) => e.index).join(', ')}`, { cause: errors });
398
+ }
399
+ return results;
400
+ });
401
+ }
402
+
354
403
  function sleep(time = 1000) {
355
404
  return new Promise((res) => {
356
405
  setTimeout(res, time);
357
406
  });
358
407
  }
359
408
 
409
+ function retry(asyncFunction, option) {
410
+ return __awaiter(this, void 0, void 0, function* () {
411
+ let retryCounts = 0;
412
+ const times = isNumber(option === null || option === void 0 ? void 0 : option.times) ? option.times : 3;
413
+ const delay = isFunction(option === null || option === void 0 ? void 0 : option.delay)
414
+ ? option.delay
415
+ : isNumber(option === null || option === void 0 ? void 0 : option.delay)
416
+ ? () => option.delay
417
+ : null;
418
+ const gap = isFunction(option === null || option === void 0 ? void 0 : option.gap) ? option.gap : isNumber(option === null || option === void 0 ? void 0 : option.gap) ? () => option.gap : null;
419
+ let lastRunTime = 0;
420
+ const getDelayTime = !option || (!delay && !gap)
421
+ ? () => 0
422
+ : gap
423
+ ? (retryCounts) => {
424
+ const time = gap(retryCounts);
425
+ return time - Date.now() + lastRunTime;
426
+ }
427
+ : delay;
428
+ while (1) {
429
+ lastRunTime = Date.now();
430
+ const [err, res] = yield tryit(asyncFunction)((err) => {
431
+ throw { $$exit_retry: err };
432
+ });
433
+ if (!err)
434
+ return res;
435
+ retryCounts++;
436
+ if (err && err.$$exit_retry)
437
+ throw err.$$exit_retry;
438
+ if (retryCounts >= times)
439
+ throw err;
440
+ const delayTime = getDelayTime(retryCounts);
441
+ if (delayTime > 0)
442
+ yield sleep(delayTime);
443
+ }
444
+ throw new Error('retry failed');
445
+ });
446
+ }
447
+
360
448
  const noop = function noop() { };
361
449
 
362
450
  function withResolvers(PromiseLike = Promise) {
@@ -370,23 +458,6 @@ function withResolvers(PromiseLike = Promise) {
370
458
  return { promise, resolve, reject };
371
459
  }
372
460
 
373
- function clamp(num, min, max, options) {
374
- var _a, _b;
375
- if (isNaN(min))
376
- throw new Error('Invalid min parameter');
377
- if (isNaN(max))
378
- throw new Error('Invalid max parameter');
379
- if (max < min) {
380
- [min, max] = [max, min];
381
- }
382
- const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
383
- const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
384
- const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
385
- if (isNaN(num))
386
- return defaultMin;
387
- return num < min ? defaultMin : num > max ? defaultMax : num;
388
- }
389
-
390
461
  const mimeMap = {
391
462
  application: {
392
463
  acrobat: ['pdf'],
@@ -1775,6 +1846,7 @@ exports.kebabCase = kebabCase;
1775
1846
  exports.memo = memo;
1776
1847
  exports.noop = noop;
1777
1848
  exports.not = not;
1849
+ exports.parallel = parallel;
1778
1850
  exports.pascalCase = pascalCase;
1779
1851
  exports.pass = pass;
1780
1852
  exports.passWith = passWith;
@@ -1787,6 +1859,7 @@ exports.randomIntFloor = randomIntFloor;
1787
1859
  exports.randomString = randomString;
1788
1860
  exports.range = range;
1789
1861
  exports.remove = remove;
1862
+ exports.retry = retry;
1790
1863
  exports.shuffle = shuffle;
1791
1864
  exports.sleep = sleep;
1792
1865
  exports.snakeCase = snakeCase;
package/lib/index.d.ts CHANGED
@@ -116,6 +116,70 @@ type DeferOption = {
116
116
  */
117
117
  declare function defer<T>(asyncFunction: (cleanUp: (fn: DeferCallbackFunction) => number, cancelCleanUp: (fnOrIndex: DeferCallbackFunction | number) => void) => T | Promise<T>, options?: Partial<DeferOption>): Promise<T>;
118
118
 
119
+ /**
120
+ * 并发执行函数, 可以控制并发数
121
+ * @param args 要经由 `fn` 处理的数据
122
+ * @param fn 处理函数, 可以是异步函数
123
+ * @param options 配置项, 目前仅支持 `limit` 限制并发数, 默认为 `5`
124
+ * @returns 一个 `Promise`, 当所有数据都处理完成后, 会返回一个包含所有结果的数组\
125
+ * 如果有错误, 则会抛出一个 `Error` 对象, `Error.cause` 中包含所有错误信息(如果环境支持的话)
126
+ * @example
127
+ * ```js
128
+ * const fn = async (n) => { return n * 2 }
129
+ * parallel([1, 2, 3, 4, 5], fn, { limit: 2 }) // Promise<[2, 4, 6, 8, 10]>
130
+ * ```
131
+ * @since 0.2.4
132
+ */
133
+ declare function parallel<Args, Res>(args: Args[], fn: (arg: Args) => Promise<Res>, options?: {
134
+ limit?: number;
135
+ }): Promise<Res[]>;
136
+
137
+ type RetryFunction<T> = (() => T | Promise<T>) | ((exitCallback: (err: any) => never) => T | Promise<T>);
138
+ type RetryOption = {
139
+ times?: number;
140
+ delay?: number | ((retryCounts: number) => number);
141
+ gap?: number | ((retryCounts: number) => number);
142
+ };
143
+ /**
144
+ * 在传入的函数发生异常后重试\
145
+ * 使用场景一般是重试网络请求等情况
146
+ * - 可以设置两次重试之间的延迟(delay), 默认为无延迟
147
+ * - 也可以设置为两次重试之间的时间间隔(gap), 与延迟模式的区别见下文
148
+ * - 传入的函数接受一个 `exit` 回调函数, 调用这个回调函数会立即退出重试逻辑
149
+ *
150
+ * 延迟模式(delay)
151
+ * ``` text
152
+ * delay = 1000:
153
+ * |0s |1s |2s |3s
154
+ * |[400ms-] | [800ms------|---] | [第 3 次调用]
155
+ * ^ 1000ms ++++|+++++++ ^ ^ 1000ms ++++++++|+++ ^
156
+ * ```
157
+ *
158
+ * 间隔模式(gap)
159
+ * ``` text
160
+ * gap = 1000:
161
+ * |0s |1s |2s
162
+ * |[400ms-] |[800ms---------] |[第 3 次调用]
163
+ * ^ 1000ms +++++++++++ ^ 1000ms +++++++++++ ^
164
+ * ```
165
+ *
166
+ * @param asyncFunction 需要处理的函数, 推荐是异步函数, 也可以是同步函数
167
+ * @param option 重试相关的配置, 具体配置见下
168
+ * @example
169
+ * ```js
170
+ * // 基本用法, 默认重试 3 次, 每次失败后会立即重新调用
171
+ * const res = await retry(() => fetch(url, params))
172
+ * // 重试 10 次
173
+ * const res = await retry(() => fetch(url, params), { times: 10 })
174
+ * // 延迟模式, 每次失败后会等待 1 秒再重新调用
175
+ * const res = await retry(() => fetch(url, params), { delay: 1000 })
176
+ * // 间隔模式, 每次失败后会在下 1 秒再重新调用
177
+ * const res = await retry(() => fetch(url, params), { gap: 1000 })
178
+ * ```
179
+ * @version 0.2.4
180
+ */
181
+ declare function retry<T>(asyncFunction: RetryFunction<T>, option?: RetryOption): Promise<T>;
182
+
119
183
  /**
120
184
  * 延迟一定时间
121
185
  * @param time 延迟时间, 单位为毫秒(ms), 默认为 `1000` (即 1 秒)
@@ -768,7 +832,7 @@ declare function isWrapperBigInt(value: unknown): value is BigInt;
768
832
  * @param options 配置项, 可以配置默认值等
769
833
  * - `default` 默认值, 如果初始值不在范围内, 则返回默认值
770
834
  * - `defaultMin` 初始值小于最小值时返回该值, 覆盖 `default` 参数
771
- * - `defaultMax` 初始值大于最大值时返回该值
835
+ * - `defaultMax` 初始值大于最大值时返回该值, 覆盖 `default` 参数
772
836
  * @returns 返回一个在指定范围内的数字
773
837
  * @example
774
838
  * ```js
@@ -1428,7 +1492,7 @@ declare function deepClone<T>(obj: T, options?: Partial<CloneOptions>, map?: Map
1428
1492
 
1429
1493
  /**
1430
1494
  * 快速深拷贝
1431
- * - 相对 `deepClone` 而言运行更快, 功能较为齐全
1495
+ * - 功能较为齐全, 相对 `deepClone` 而言运行更快
1432
1496
  * - 支持处理的情况:循环引用、数组、`Date`、正则、`Set`、`Map`、`FormData`
1433
1497
  * - 对象上以 `Symbol` 为键的属性无法拷贝
1434
1498
  * - 无法拷贝的内容将视为原生数据类型, 直接复制(如函数、`Promise`、`WeakMap`、`WeakSet`)
@@ -1673,4 +1737,4 @@ declare function throttle<T extends any[]>(fn: (...args: T) => any, delay: numbe
1673
1737
  reset: () => void;
1674
1738
  };
1675
1739
 
1676
- export { type CloneOptions, type CustomCloner, type RangeOptions, type TypedArray, _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, defer, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uuidNil, uuidV4, withResolvers };
1740
+ export { type CloneOptions, type CustomCloner, type RangeOptions, type TypedArray, _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, defer, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, parallel, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, retry, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uuidNil, uuidV4, withResolvers };
package/lib/index.mjs CHANGED
@@ -349,12 +349,100 @@ function defer(asyncFunction, options) {
349
349
  });
350
350
  }
351
351
 
352
+ function clamp(num, min, max, options) {
353
+ var _a, _b;
354
+ if (isNaN(min))
355
+ throw new Error('Invalid min parameter');
356
+ if (isNaN(max))
357
+ throw new Error('Invalid max parameter');
358
+ if (max < min) {
359
+ [min, max] = [max, min];
360
+ }
361
+ const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
362
+ const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
363
+ const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
364
+ if (isNaN(num))
365
+ return defaultMin;
366
+ return num < min ? defaultMin : num > max ? defaultMax : num;
367
+ }
368
+
369
+ function parallel(args, fn, options) {
370
+ return __awaiter(this, void 0, void 0, function* () {
371
+ if (!args.length)
372
+ return [];
373
+ const { limit: _limit = 5 } = options || {};
374
+ const limit = clamp(Math.floor(_limit), 1, 100);
375
+ let current = 0;
376
+ const results = [];
377
+ const errors = [];
378
+ const asyncFn = tryit(fn);
379
+ const processor = () => __awaiter(this, void 0, void 0, function* () {
380
+ while (current < args.length) {
381
+ const index = current++;
382
+ const [err, result] = yield asyncFn(args[index]);
383
+ if (err)
384
+ errors.push({ index, error: err });
385
+ else
386
+ results[index] = result;
387
+ }
388
+ });
389
+ const tasks = [];
390
+ for (let i = 0; i < Math.min(args.length, limit); i++) {
391
+ tasks.push(processor());
392
+ }
393
+ yield Promise.all(tasks);
394
+ if (errors.length) {
395
+ throw new Error(`Parallel execution failed on index: ${errors.map((e) => e.index).join(', ')}`, { cause: errors });
396
+ }
397
+ return results;
398
+ });
399
+ }
400
+
352
401
  function sleep(time = 1000) {
353
402
  return new Promise((res) => {
354
403
  setTimeout(res, time);
355
404
  });
356
405
  }
357
406
 
407
+ function retry(asyncFunction, option) {
408
+ return __awaiter(this, void 0, void 0, function* () {
409
+ let retryCounts = 0;
410
+ const times = isNumber(option === null || option === void 0 ? void 0 : option.times) ? option.times : 3;
411
+ const delay = isFunction(option === null || option === void 0 ? void 0 : option.delay)
412
+ ? option.delay
413
+ : isNumber(option === null || option === void 0 ? void 0 : option.delay)
414
+ ? () => option.delay
415
+ : null;
416
+ const gap = isFunction(option === null || option === void 0 ? void 0 : option.gap) ? option.gap : isNumber(option === null || option === void 0 ? void 0 : option.gap) ? () => option.gap : null;
417
+ let lastRunTime = 0;
418
+ const getDelayTime = !option || (!delay && !gap)
419
+ ? () => 0
420
+ : gap
421
+ ? (retryCounts) => {
422
+ const time = gap(retryCounts);
423
+ return time - Date.now() + lastRunTime;
424
+ }
425
+ : delay;
426
+ while (1) {
427
+ lastRunTime = Date.now();
428
+ const [err, res] = yield tryit(asyncFunction)((err) => {
429
+ throw { $$exit_retry: err };
430
+ });
431
+ if (!err)
432
+ return res;
433
+ retryCounts++;
434
+ if (err && err.$$exit_retry)
435
+ throw err.$$exit_retry;
436
+ if (retryCounts >= times)
437
+ throw err;
438
+ const delayTime = getDelayTime(retryCounts);
439
+ if (delayTime > 0)
440
+ yield sleep(delayTime);
441
+ }
442
+ throw new Error('retry failed');
443
+ });
444
+ }
445
+
358
446
  const noop = function noop() { };
359
447
 
360
448
  function withResolvers(PromiseLike = Promise) {
@@ -368,23 +456,6 @@ function withResolvers(PromiseLike = Promise) {
368
456
  return { promise, resolve, reject };
369
457
  }
370
458
 
371
- function clamp(num, min, max, options) {
372
- var _a, _b;
373
- if (isNaN(min))
374
- throw new Error('Invalid min parameter');
375
- if (isNaN(max))
376
- throw new Error('Invalid max parameter');
377
- if (max < min) {
378
- [min, max] = [max, min];
379
- }
380
- const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
381
- const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
382
- const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
383
- if (isNaN(num))
384
- return defaultMin;
385
- return num < min ? defaultMin : num > max ? defaultMax : num;
386
- }
387
-
388
459
  const mimeMap = {
389
460
  application: {
390
461
  acrobat: ['pdf'],
@@ -1701,4 +1772,4 @@ function throttle(fn, delay, options) {
1701
1772
  return _throttle(fn, delay, Object.assign({ trailing: false, leading: true }, options));
1702
1773
  }
1703
1774
 
1704
- export { _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, defer, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uuidNil, uuidV4, withResolvers };
1775
+ export { _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, defer, fastClone, getAcceptableExtByMIME, getAcceptableMIMEByExt, getGlobalThis, getTag, isArray, isArrayBuffer, isArrayLike, isBigInt, isBigInt64Array, isBigUint64Array, isBoolean, isBuffer, isDataView, isDate, isEmpty, isFile, isFloat32Array, isFloat64Array, isFormData, isFunction, isInt16Array, isInt32Array, isInt8Array, isInteger, isIterable, isMap, isNil, isNull, isNumber, isObject, isPlaceholder, isPrimitive, isPromise, isPromiseLike, isRegExp, isSet, isString, isSymbol, isTypedArray, isUint16Array, isUint32Array, isUint8Array, isUint8ClampedArray, isUndefined, isWeakMap, isWeakSet, isWrapperBigInt, isWrapperBoolean, isWrapperNumber, isWrapperObject, isWrapperString, isWrapperSymbol, kebabCase, memo, noop, not, parallel, pascalCase, pass, passWith, pipe, randomBase32String, randomChoice, randomHexString, randomInt, randomIntFloor, randomString, range, remove, retry, shuffle, sleep, snakeCase, splitWords, throttle, titleCase, tryit, ulid, uuidNil, uuidV4, withResolvers };
package/lib/index.umd.js CHANGED
@@ -355,12 +355,100 @@ See the Mulan PSL v2 for more details.
355
355
  });
356
356
  }
357
357
 
358
+ function clamp(num, min, max, options) {
359
+ var _a, _b;
360
+ if (isNaN(min))
361
+ throw new Error('Invalid min parameter');
362
+ if (isNaN(max))
363
+ throw new Error('Invalid max parameter');
364
+ if (max < min) {
365
+ [min, max] = [max, min];
366
+ }
367
+ const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
368
+ const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
369
+ const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
370
+ if (isNaN(num))
371
+ return defaultMin;
372
+ return num < min ? defaultMin : num > max ? defaultMax : num;
373
+ }
374
+
375
+ function parallel(args, fn, options) {
376
+ return __awaiter(this, void 0, void 0, function* () {
377
+ if (!args.length)
378
+ return [];
379
+ const { limit: _limit = 5 } = options || {};
380
+ const limit = clamp(Math.floor(_limit), 1, 100);
381
+ let current = 0;
382
+ const results = [];
383
+ const errors = [];
384
+ const asyncFn = tryit(fn);
385
+ const processor = () => __awaiter(this, void 0, void 0, function* () {
386
+ while (current < args.length) {
387
+ const index = current++;
388
+ const [err, result] = yield asyncFn(args[index]);
389
+ if (err)
390
+ errors.push({ index, error: err });
391
+ else
392
+ results[index] = result;
393
+ }
394
+ });
395
+ const tasks = [];
396
+ for (let i = 0; i < Math.min(args.length, limit); i++) {
397
+ tasks.push(processor());
398
+ }
399
+ yield Promise.all(tasks);
400
+ if (errors.length) {
401
+ throw new Error(`Parallel execution failed on index: ${errors.map((e) => e.index).join(', ')}`, { cause: errors });
402
+ }
403
+ return results;
404
+ });
405
+ }
406
+
358
407
  function sleep(time = 1000) {
359
408
  return new Promise((res) => {
360
409
  setTimeout(res, time);
361
410
  });
362
411
  }
363
412
 
413
+ function retry(asyncFunction, option) {
414
+ return __awaiter(this, void 0, void 0, function* () {
415
+ let retryCounts = 0;
416
+ const times = isNumber(option === null || option === void 0 ? void 0 : option.times) ? option.times : 3;
417
+ const delay = isFunction(option === null || option === void 0 ? void 0 : option.delay)
418
+ ? option.delay
419
+ : isNumber(option === null || option === void 0 ? void 0 : option.delay)
420
+ ? () => option.delay
421
+ : null;
422
+ const gap = isFunction(option === null || option === void 0 ? void 0 : option.gap) ? option.gap : isNumber(option === null || option === void 0 ? void 0 : option.gap) ? () => option.gap : null;
423
+ let lastRunTime = 0;
424
+ const getDelayTime = !option || (!delay && !gap)
425
+ ? () => 0
426
+ : gap
427
+ ? (retryCounts) => {
428
+ const time = gap(retryCounts);
429
+ return time - Date.now() + lastRunTime;
430
+ }
431
+ : delay;
432
+ while (1) {
433
+ lastRunTime = Date.now();
434
+ const [err, res] = yield tryit(asyncFunction)((err) => {
435
+ throw { $$exit_retry: err };
436
+ });
437
+ if (!err)
438
+ return res;
439
+ retryCounts++;
440
+ if (err && err.$$exit_retry)
441
+ throw err.$$exit_retry;
442
+ if (retryCounts >= times)
443
+ throw err;
444
+ const delayTime = getDelayTime(retryCounts);
445
+ if (delayTime > 0)
446
+ yield sleep(delayTime);
447
+ }
448
+ throw new Error('retry failed');
449
+ });
450
+ }
451
+
364
452
  const noop = function noop() { };
365
453
 
366
454
  function withResolvers(PromiseLike = Promise) {
@@ -374,23 +462,6 @@ See the Mulan PSL v2 for more details.
374
462
  return { promise, resolve, reject };
375
463
  }
376
464
 
377
- function clamp(num, min, max, options) {
378
- var _a, _b;
379
- if (isNaN(min))
380
- throw new Error('Invalid min parameter');
381
- if (isNaN(max))
382
- throw new Error('Invalid max parameter');
383
- if (max < min) {
384
- [min, max] = [max, min];
385
- }
386
- const { default: def, defaultMin: _dMin, defaultMax: _dMax } = options || {};
387
- const defaultMin = (_a = _dMin !== null && _dMin !== void 0 ? _dMin : def) !== null && _a !== void 0 ? _a : min;
388
- const defaultMax = (_b = _dMax !== null && _dMax !== void 0 ? _dMax : def) !== null && _b !== void 0 ? _b : max;
389
- if (isNaN(num))
390
- return defaultMin;
391
- return num < min ? defaultMin : num > max ? defaultMax : num;
392
- }
393
-
394
465
  const mimeMap = {
395
466
  application: {
396
467
  acrobat: ['pdf'],
@@ -1779,6 +1850,7 @@ See the Mulan PSL v2 for more details.
1779
1850
  exports.memo = memo;
1780
1851
  exports.noop = noop;
1781
1852
  exports.not = not;
1853
+ exports.parallel = parallel;
1782
1854
  exports.pascalCase = pascalCase;
1783
1855
  exports.pass = pass;
1784
1856
  exports.passWith = passWith;
@@ -1791,6 +1863,7 @@ See the Mulan PSL v2 for more details.
1791
1863
  exports.randomString = randomString;
1792
1864
  exports.range = range;
1793
1865
  exports.remove = remove;
1866
+ exports.retry = retry;
1794
1867
  exports.shuffle = shuffle;
1795
1868
  exports.sleep = sleep;
1796
1869
  exports.snakeCase = snakeCase;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "foreslash",
3
- "version": "0.2.3",
3
+ "version": "0.2.4",
4
4
  "description": "Foreslash is a Javascript utilities lib which contains plenty of practical functions.",
5
5
  "author": "moushu",
6
6
  "license": "Mulan PSL v2",