foreslash 0.2.2 → 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 +26 -0
- package/lib/index.cmn.cjs +162 -19
- package/lib/index.d.ts +109 -3
- package/lib/index.mjs +160 -20
- package/lib/index.umd.js +162 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,31 @@
|
|
|
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
|
+
|
|
15
|
+
## Version 0.2.3 - 2025-03-28
|
|
16
|
+
|
|
17
|
+
Unstable version
|
|
18
|
+
|
|
19
|
+
- Feat 🥥 Functions added: `defer`
|
|
20
|
+
- Fix 🥕 Bug fixed: `debounce` doesn't apply the last callee's arguments
|
|
21
|
+
- Other fixes and improvements
|
|
22
|
+
|
|
23
|
+
不稳定版本
|
|
24
|
+
|
|
25
|
+
- 功能 🥥 添加函数: `defer`
|
|
26
|
+
- 修复 🥕 缺陷修复: `debounce` 没有传入最后一次获取的参数
|
|
27
|
+
- 其他修复与优化
|
|
28
|
+
|
|
3
29
|
## Version 0.2.2 - 2025-03-18
|
|
4
30
|
|
|
5
31
|
Unstable version
|
package/lib/index.cmn.cjs
CHANGED
|
@@ -67,11 +67,37 @@ function remove(arr, ...item) {
|
|
|
67
67
|
return res;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
/******************************************************************************
|
|
71
|
+
Copyright (c) Microsoft Corporation.
|
|
72
|
+
|
|
73
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
74
|
+
purpose with or without fee is hereby granted.
|
|
75
|
+
|
|
76
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
77
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
78
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
79
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
80
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
81
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
82
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
83
|
+
***************************************************************************** */
|
|
84
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
88
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
89
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
90
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
91
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
92
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
93
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
98
|
+
var e = new Error(message);
|
|
99
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
100
|
+
};
|
|
75
101
|
|
|
76
102
|
const isArray = Array.isArray;
|
|
77
103
|
|
|
@@ -171,7 +197,7 @@ function isNumber(value) {
|
|
|
171
197
|
}
|
|
172
198
|
|
|
173
199
|
function isPrimitive(value) {
|
|
174
|
-
return value
|
|
200
|
+
return value === undefined || value === null || (typeof value !== 'object' && typeof value !== 'function');
|
|
175
201
|
}
|
|
176
202
|
|
|
177
203
|
function isPromise(value) {
|
|
@@ -292,17 +318,37 @@ function tryit(fn) {
|
|
|
292
318
|
};
|
|
293
319
|
}
|
|
294
320
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
321
|
+
function defer(asyncFunction, options) {
|
|
322
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
323
|
+
const queue = [];
|
|
324
|
+
const { rethrow = false } = options || {};
|
|
325
|
+
const defaultOption = { rethrow };
|
|
326
|
+
const cleanUp = (fn, options) => {
|
|
327
|
+
queue.push({ fn, opt: Object.assign(defaultOption, options) });
|
|
328
|
+
return queue.length - 1;
|
|
329
|
+
};
|
|
330
|
+
const cancelCleanUp = (fnOrIndex) => {
|
|
331
|
+
if (isInteger(fnOrIndex) && fnOrIndex > -1)
|
|
332
|
+
queue[fnOrIndex] = null;
|
|
333
|
+
else if (isFunction(fnOrIndex)) {
|
|
334
|
+
const i = queue.findIndex((item) => item && item.fn === fnOrIndex);
|
|
335
|
+
if (i > -1)
|
|
336
|
+
queue[i] = null;
|
|
337
|
+
}
|
|
338
|
+
};
|
|
339
|
+
const [err, res] = yield tryit(asyncFunction)(cleanUp, cancelCleanUp);
|
|
340
|
+
for (const item of queue) {
|
|
341
|
+
if (!item)
|
|
342
|
+
continue;
|
|
343
|
+
const { fn, opt } = item;
|
|
344
|
+
const [cleanUpErr] = yield tryit(fn)(err);
|
|
345
|
+
if (cleanUpErr && opt.rethrow)
|
|
346
|
+
throw cleanUpErr;
|
|
347
|
+
}
|
|
348
|
+
if (err)
|
|
349
|
+
throw err;
|
|
350
|
+
return res;
|
|
304
351
|
});
|
|
305
|
-
return { promise, resolve, reject };
|
|
306
352
|
}
|
|
307
353
|
|
|
308
354
|
function clamp(num, min, max, options) {
|
|
@@ -322,6 +368,96 @@ function clamp(num, min, max, options) {
|
|
|
322
368
|
return num < min ? defaultMin : num > max ? defaultMax : num;
|
|
323
369
|
}
|
|
324
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
|
+
|
|
403
|
+
function sleep(time = 1000) {
|
|
404
|
+
return new Promise((res) => {
|
|
405
|
+
setTimeout(res, time);
|
|
406
|
+
});
|
|
407
|
+
}
|
|
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
|
+
|
|
448
|
+
const noop = function noop() { };
|
|
449
|
+
|
|
450
|
+
function withResolvers(PromiseLike = Promise) {
|
|
451
|
+
let promise;
|
|
452
|
+
let resolve = noop;
|
|
453
|
+
let reject = noop;
|
|
454
|
+
promise = new PromiseLike((res, rej) => {
|
|
455
|
+
resolve = res;
|
|
456
|
+
reject = rej;
|
|
457
|
+
});
|
|
458
|
+
return { promise, resolve, reject };
|
|
459
|
+
}
|
|
460
|
+
|
|
325
461
|
const mimeMap = {
|
|
326
462
|
application: {
|
|
327
463
|
acrobat: ['pdf'],
|
|
@@ -1321,9 +1457,10 @@ function _curryMore(fn) {
|
|
|
1321
1457
|
}
|
|
1322
1458
|
|
|
1323
1459
|
function _throttle(fn, delay, options) {
|
|
1324
|
-
var _a, _b;
|
|
1460
|
+
var _a, _b, _c;
|
|
1325
1461
|
const trailing = (_a = options === null || options === void 0 ? void 0 : options.trailing) !== null && _a !== void 0 ? _a : false;
|
|
1326
|
-
const
|
|
1462
|
+
const trailingRunLast = (_b = options === null || options === void 0 ? void 0 : options.trailingRunLast) !== null && _b !== void 0 ? _b : true;
|
|
1463
|
+
const leading = (_c = options === null || options === void 0 ? void 0 : options.leading) !== null && _c !== void 0 ? _c : true;
|
|
1327
1464
|
let timer = null;
|
|
1328
1465
|
let lastTime = 0;
|
|
1329
1466
|
const clearTimer = () => {
|
|
@@ -1343,6 +1480,9 @@ function _throttle(fn, delay, options) {
|
|
|
1343
1480
|
lastTime = now;
|
|
1344
1481
|
clearTimer();
|
|
1345
1482
|
}
|
|
1483
|
+
if (timeGap < 0 && trailing && trailingRunLast && timer) {
|
|
1484
|
+
clearTimer();
|
|
1485
|
+
}
|
|
1346
1486
|
if (timeGap >= 0 && leading) {
|
|
1347
1487
|
fn.apply(this, args);
|
|
1348
1488
|
}
|
|
@@ -1360,7 +1500,7 @@ function debounce(fn, delay, options) {
|
|
|
1360
1500
|
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1361
1501
|
throw new Error('Invalid delay parameter');
|
|
1362
1502
|
}
|
|
1363
|
-
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false }, options));
|
|
1503
|
+
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false, trailingRunLast: true }, options));
|
|
1364
1504
|
}
|
|
1365
1505
|
|
|
1366
1506
|
function _cloneArray(obj, map, cloner, ...args) {
|
|
@@ -1648,6 +1788,7 @@ exports.compose = compose;
|
|
|
1648
1788
|
exports.curry = _curryMore;
|
|
1649
1789
|
exports.debounce = debounce;
|
|
1650
1790
|
exports.deepClone = deepClone;
|
|
1791
|
+
exports.defer = defer;
|
|
1651
1792
|
exports.fastClone = fastClone;
|
|
1652
1793
|
exports.getAcceptableExtByMIME = getAcceptableExtByMIME;
|
|
1653
1794
|
exports.getAcceptableMIMEByExt = getAcceptableMIMEByExt;
|
|
@@ -1705,6 +1846,7 @@ exports.kebabCase = kebabCase;
|
|
|
1705
1846
|
exports.memo = memo;
|
|
1706
1847
|
exports.noop = noop;
|
|
1707
1848
|
exports.not = not;
|
|
1849
|
+
exports.parallel = parallel;
|
|
1708
1850
|
exports.pascalCase = pascalCase;
|
|
1709
1851
|
exports.pass = pass;
|
|
1710
1852
|
exports.passWith = passWith;
|
|
@@ -1717,6 +1859,7 @@ exports.randomIntFloor = randomIntFloor;
|
|
|
1717
1859
|
exports.randomString = randomString;
|
|
1718
1860
|
exports.range = range;
|
|
1719
1861
|
exports.remove = remove;
|
|
1862
|
+
exports.retry = retry;
|
|
1720
1863
|
exports.shuffle = shuffle;
|
|
1721
1864
|
exports.sleep = sleep;
|
|
1722
1865
|
exports.snakeCase = snakeCase;
|
package/lib/index.d.ts
CHANGED
|
@@ -77,6 +77,109 @@ declare function range<T = number>(start: number, end: number, options?: RangeOp
|
|
|
77
77
|
*/
|
|
78
78
|
declare function remove<T>(arr: ArrayLike<T>, ...item: (T | ((val: T) => unknown))[]): T[];
|
|
79
79
|
|
|
80
|
+
type DeferCallbackFunction = (error?: Error) => unknown;
|
|
81
|
+
type DeferOption = {
|
|
82
|
+
rethrow: boolean;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* 在传入的函数执行完毕后(或是抛出异常后), 执行*延迟操作*\
|
|
86
|
+
* 使用场景一般是处理“副作用”, 类似 `try {} finally {}` 结构但是更加灵活
|
|
87
|
+
* - 执行*延迟操作*的时机是函数执行完毕后(或是抛出异常后), 同时 `defer` 返回的 `Promise` 并未结束
|
|
88
|
+
* - 这个设计是防止*延迟操作*与后续逻辑产生干扰
|
|
89
|
+
* - `defer` 返回的 `Promise` 会根据传入的函数是否正常处理/抛出异常而变化
|
|
90
|
+
* - 传入的函数正常处理, 结果为 `1`, 那么 `defer` 将返回 `Promise {<fulfilled>: 1}`
|
|
91
|
+
* - 传入的函数抛出异常, 内容为 `2`, 那么 `defer` 将返回 `Promise {<rejected>: 2}`
|
|
92
|
+
*
|
|
93
|
+
* *延迟操作*时抛出的错误不会正常抛出
|
|
94
|
+
* - 如果希望执行*延迟操作*时正常抛错, 您可以配置 `options.rethrow = true`
|
|
95
|
+
* @param asyncFunction 需要在执行完毕后做额外处理函数
|
|
96
|
+
* @param options.rethrow 执行*延迟操作*时是否正常抛错, 默认不抛错
|
|
97
|
+
* @returns 一个 `Promise` 会根据传入的函数是否正常处理/抛出异常而变化
|
|
98
|
+
* @example
|
|
99
|
+
* ```js
|
|
100
|
+
* // 一般用途
|
|
101
|
+
* defer((cleanUp) => {
|
|
102
|
+
* cleanUp(() => console.log(2))
|
|
103
|
+
* cleanUp(() => console.log(3))
|
|
104
|
+
* console.log(1)
|
|
105
|
+
* }) // 依次输出 1 2 3
|
|
106
|
+
* // 可以动态取消计划好的延迟操作
|
|
107
|
+
* defer((cleanUp, cancelCleanUp) => {
|
|
108
|
+
* const cleanUpId = cleanUp(() => console.log(123)) // 会返回一个数字作为 id
|
|
109
|
+
* cleanUp(() => console.log(5))
|
|
110
|
+
* cleanUp(() => console.log(6))
|
|
111
|
+
* console.log(4)
|
|
112
|
+
* cancelCleanUp(cleanUpId) // 可以用于取消指定的延迟操作
|
|
113
|
+
* }) // 依次输出 4 5 6
|
|
114
|
+
* ```
|
|
115
|
+
* @version 0.2.3
|
|
116
|
+
*/
|
|
117
|
+
declare function defer<T>(asyncFunction: (cleanUp: (fn: DeferCallbackFunction) => number, cancelCleanUp: (fnOrIndex: DeferCallbackFunction | number) => void) => T | Promise<T>, options?: Partial<DeferOption>): Promise<T>;
|
|
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
|
+
|
|
80
183
|
/**
|
|
81
184
|
* 延迟一定时间
|
|
82
185
|
* @param time 延迟时间, 单位为毫秒(ms), 默认为 `1000` (即 1 秒)
|
|
@@ -729,7 +832,7 @@ declare function isWrapperBigInt(value: unknown): value is BigInt;
|
|
|
729
832
|
* @param options 配置项, 可以配置默认值等
|
|
730
833
|
* - `default` 默认值, 如果初始值不在范围内, 则返回默认值
|
|
731
834
|
* - `defaultMin` 初始值小于最小值时返回该值, 覆盖 `default` 参数
|
|
732
|
-
* - `defaultMax`
|
|
835
|
+
* - `defaultMax` 初始值大于最大值时返回该值, 覆盖 `default` 参数
|
|
733
836
|
* @returns 返回一个在指定范围内的数字
|
|
734
837
|
* @example
|
|
735
838
|
* ```js
|
|
@@ -740,6 +843,7 @@ declare function isWrapperBigInt(value: unknown): value is BigInt;
|
|
|
740
843
|
* clamp(15, 0, 10, { default: 6 }) // 6
|
|
741
844
|
* clamp(-5, 0, 10, { default: 6 }) // 6
|
|
742
845
|
* ```
|
|
846
|
+
* @version 0.2.2
|
|
743
847
|
*/
|
|
744
848
|
declare function clamp(num: number, min: number, max: number, options?: {
|
|
745
849
|
default?: number;
|
|
@@ -1320,6 +1424,8 @@ declare function _curryMore<Args extends Array<any>, Res>(fn: (...args: Args) =>
|
|
|
1320
1424
|
interface ThrottleOptions {
|
|
1321
1425
|
/** 节流时触发的最后一次调用是否执行, 默认为否 */
|
|
1322
1426
|
trailing?: boolean;
|
|
1427
|
+
/** 触发的最后一次调用是否使用最后一次的参数, 默认为是 */
|
|
1428
|
+
trailingRunLast?: boolean;
|
|
1323
1429
|
/** 第一次触发是否直接执行, 默认为是 */
|
|
1324
1430
|
leading?: boolean;
|
|
1325
1431
|
}
|
|
@@ -1386,7 +1492,7 @@ declare function deepClone<T>(obj: T, options?: Partial<CloneOptions>, map?: Map
|
|
|
1386
1492
|
|
|
1387
1493
|
/**
|
|
1388
1494
|
* 快速深拷贝
|
|
1389
|
-
* - 相对 `deepClone`
|
|
1495
|
+
* - 功能较为齐全, 相对 `deepClone` 而言运行更快
|
|
1390
1496
|
* - 支持处理的情况:循环引用、数组、`Date`、正则、`Set`、`Map`、`FormData`
|
|
1391
1497
|
* - 对象上以 `Symbol` 为键的属性无法拷贝
|
|
1392
1498
|
* - 无法拷贝的内容将视为原生数据类型, 直接复制(如函数、`Promise`、`WeakMap`、`WeakSet`)
|
|
@@ -1631,4 +1737,4 @@ declare function throttle<T extends any[]>(fn: (...args: T) => any, delay: numbe
|
|
|
1631
1737
|
reset: () => void;
|
|
1632
1738
|
};
|
|
1633
1739
|
|
|
1634
|
-
export { type CloneOptions, type CustomCloner, type RangeOptions, type TypedArray, _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, 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
|
@@ -65,11 +65,37 @@ function remove(arr, ...item) {
|
|
|
65
65
|
return res;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
68
|
+
/******************************************************************************
|
|
69
|
+
Copyright (c) Microsoft Corporation.
|
|
70
|
+
|
|
71
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
72
|
+
purpose with or without fee is hereby granted.
|
|
73
|
+
|
|
74
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
75
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
76
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
77
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
78
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
79
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
80
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
81
|
+
***************************************************************************** */
|
|
82
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
86
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
87
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
88
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
89
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
90
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
91
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
96
|
+
var e = new Error(message);
|
|
97
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
98
|
+
};
|
|
73
99
|
|
|
74
100
|
const isArray = Array.isArray;
|
|
75
101
|
|
|
@@ -169,7 +195,7 @@ function isNumber(value) {
|
|
|
169
195
|
}
|
|
170
196
|
|
|
171
197
|
function isPrimitive(value) {
|
|
172
|
-
return value
|
|
198
|
+
return value === undefined || value === null || (typeof value !== 'object' && typeof value !== 'function');
|
|
173
199
|
}
|
|
174
200
|
|
|
175
201
|
function isPromise(value) {
|
|
@@ -290,17 +316,37 @@ function tryit(fn) {
|
|
|
290
316
|
};
|
|
291
317
|
}
|
|
292
318
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
319
|
+
function defer(asyncFunction, options) {
|
|
320
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
321
|
+
const queue = [];
|
|
322
|
+
const { rethrow = false } = options || {};
|
|
323
|
+
const defaultOption = { rethrow };
|
|
324
|
+
const cleanUp = (fn, options) => {
|
|
325
|
+
queue.push({ fn, opt: Object.assign(defaultOption, options) });
|
|
326
|
+
return queue.length - 1;
|
|
327
|
+
};
|
|
328
|
+
const cancelCleanUp = (fnOrIndex) => {
|
|
329
|
+
if (isInteger(fnOrIndex) && fnOrIndex > -1)
|
|
330
|
+
queue[fnOrIndex] = null;
|
|
331
|
+
else if (isFunction(fnOrIndex)) {
|
|
332
|
+
const i = queue.findIndex((item) => item && item.fn === fnOrIndex);
|
|
333
|
+
if (i > -1)
|
|
334
|
+
queue[i] = null;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
const [err, res] = yield tryit(asyncFunction)(cleanUp, cancelCleanUp);
|
|
338
|
+
for (const item of queue) {
|
|
339
|
+
if (!item)
|
|
340
|
+
continue;
|
|
341
|
+
const { fn, opt } = item;
|
|
342
|
+
const [cleanUpErr] = yield tryit(fn)(err);
|
|
343
|
+
if (cleanUpErr && opt.rethrow)
|
|
344
|
+
throw cleanUpErr;
|
|
345
|
+
}
|
|
346
|
+
if (err)
|
|
347
|
+
throw err;
|
|
348
|
+
return res;
|
|
302
349
|
});
|
|
303
|
-
return { promise, resolve, reject };
|
|
304
350
|
}
|
|
305
351
|
|
|
306
352
|
function clamp(num, min, max, options) {
|
|
@@ -320,6 +366,96 @@ function clamp(num, min, max, options) {
|
|
|
320
366
|
return num < min ? defaultMin : num > max ? defaultMax : num;
|
|
321
367
|
}
|
|
322
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
|
+
|
|
401
|
+
function sleep(time = 1000) {
|
|
402
|
+
return new Promise((res) => {
|
|
403
|
+
setTimeout(res, time);
|
|
404
|
+
});
|
|
405
|
+
}
|
|
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
|
+
|
|
446
|
+
const noop = function noop() { };
|
|
447
|
+
|
|
448
|
+
function withResolvers(PromiseLike = Promise) {
|
|
449
|
+
let promise;
|
|
450
|
+
let resolve = noop;
|
|
451
|
+
let reject = noop;
|
|
452
|
+
promise = new PromiseLike((res, rej) => {
|
|
453
|
+
resolve = res;
|
|
454
|
+
reject = rej;
|
|
455
|
+
});
|
|
456
|
+
return { promise, resolve, reject };
|
|
457
|
+
}
|
|
458
|
+
|
|
323
459
|
const mimeMap = {
|
|
324
460
|
application: {
|
|
325
461
|
acrobat: ['pdf'],
|
|
@@ -1319,9 +1455,10 @@ function _curryMore(fn) {
|
|
|
1319
1455
|
}
|
|
1320
1456
|
|
|
1321
1457
|
function _throttle(fn, delay, options) {
|
|
1322
|
-
var _a, _b;
|
|
1458
|
+
var _a, _b, _c;
|
|
1323
1459
|
const trailing = (_a = options === null || options === void 0 ? void 0 : options.trailing) !== null && _a !== void 0 ? _a : false;
|
|
1324
|
-
const
|
|
1460
|
+
const trailingRunLast = (_b = options === null || options === void 0 ? void 0 : options.trailingRunLast) !== null && _b !== void 0 ? _b : true;
|
|
1461
|
+
const leading = (_c = options === null || options === void 0 ? void 0 : options.leading) !== null && _c !== void 0 ? _c : true;
|
|
1325
1462
|
let timer = null;
|
|
1326
1463
|
let lastTime = 0;
|
|
1327
1464
|
const clearTimer = () => {
|
|
@@ -1341,6 +1478,9 @@ function _throttle(fn, delay, options) {
|
|
|
1341
1478
|
lastTime = now;
|
|
1342
1479
|
clearTimer();
|
|
1343
1480
|
}
|
|
1481
|
+
if (timeGap < 0 && trailing && trailingRunLast && timer) {
|
|
1482
|
+
clearTimer();
|
|
1483
|
+
}
|
|
1344
1484
|
if (timeGap >= 0 && leading) {
|
|
1345
1485
|
fn.apply(this, args);
|
|
1346
1486
|
}
|
|
@@ -1358,7 +1498,7 @@ function debounce(fn, delay, options) {
|
|
|
1358
1498
|
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1359
1499
|
throw new Error('Invalid delay parameter');
|
|
1360
1500
|
}
|
|
1361
|
-
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false }, options));
|
|
1501
|
+
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false, trailingRunLast: true }, options));
|
|
1362
1502
|
}
|
|
1363
1503
|
|
|
1364
1504
|
function _cloneArray(obj, map, cloner, ...args) {
|
|
@@ -1632,4 +1772,4 @@ function throttle(fn, delay, options) {
|
|
|
1632
1772
|
return _throttle(fn, delay, Object.assign({ trailing: false, leading: true }, options));
|
|
1633
1773
|
}
|
|
1634
1774
|
|
|
1635
|
-
export { _, acceptableFileName, acceptableFileType, camelCase, caseCamel, caseConvert, caseKebab, casePascal, caseSnake, clamp, compose, _curryMore as curry, debounce, deepClone, 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
|
@@ -71,11 +71,37 @@ See the Mulan PSL v2 for more details.
|
|
|
71
71
|
return res;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
/******************************************************************************
|
|
75
|
+
Copyright (c) Microsoft Corporation.
|
|
76
|
+
|
|
77
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
78
|
+
purpose with or without fee is hereby granted.
|
|
79
|
+
|
|
80
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
81
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
82
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
83
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
84
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
85
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
86
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
87
|
+
***************************************************************************** */
|
|
88
|
+
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
function __awaiter(thisArg, _arguments, P, generator) {
|
|
92
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
93
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
94
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
95
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
96
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
97
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
|
|
102
|
+
var e = new Error(message);
|
|
103
|
+
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
|
|
104
|
+
};
|
|
79
105
|
|
|
80
106
|
const isArray = Array.isArray;
|
|
81
107
|
|
|
@@ -175,7 +201,7 @@ See the Mulan PSL v2 for more details.
|
|
|
175
201
|
}
|
|
176
202
|
|
|
177
203
|
function isPrimitive(value) {
|
|
178
|
-
return value
|
|
204
|
+
return value === undefined || value === null || (typeof value !== 'object' && typeof value !== 'function');
|
|
179
205
|
}
|
|
180
206
|
|
|
181
207
|
function isPromise(value) {
|
|
@@ -296,17 +322,37 @@ See the Mulan PSL v2 for more details.
|
|
|
296
322
|
};
|
|
297
323
|
}
|
|
298
324
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
325
|
+
function defer(asyncFunction, options) {
|
|
326
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
327
|
+
const queue = [];
|
|
328
|
+
const { rethrow = false } = options || {};
|
|
329
|
+
const defaultOption = { rethrow };
|
|
330
|
+
const cleanUp = (fn, options) => {
|
|
331
|
+
queue.push({ fn, opt: Object.assign(defaultOption, options) });
|
|
332
|
+
return queue.length - 1;
|
|
333
|
+
};
|
|
334
|
+
const cancelCleanUp = (fnOrIndex) => {
|
|
335
|
+
if (isInteger(fnOrIndex) && fnOrIndex > -1)
|
|
336
|
+
queue[fnOrIndex] = null;
|
|
337
|
+
else if (isFunction(fnOrIndex)) {
|
|
338
|
+
const i = queue.findIndex((item) => item && item.fn === fnOrIndex);
|
|
339
|
+
if (i > -1)
|
|
340
|
+
queue[i] = null;
|
|
341
|
+
}
|
|
342
|
+
};
|
|
343
|
+
const [err, res] = yield tryit(asyncFunction)(cleanUp, cancelCleanUp);
|
|
344
|
+
for (const item of queue) {
|
|
345
|
+
if (!item)
|
|
346
|
+
continue;
|
|
347
|
+
const { fn, opt } = item;
|
|
348
|
+
const [cleanUpErr] = yield tryit(fn)(err);
|
|
349
|
+
if (cleanUpErr && opt.rethrow)
|
|
350
|
+
throw cleanUpErr;
|
|
351
|
+
}
|
|
352
|
+
if (err)
|
|
353
|
+
throw err;
|
|
354
|
+
return res;
|
|
308
355
|
});
|
|
309
|
-
return { promise, resolve, reject };
|
|
310
356
|
}
|
|
311
357
|
|
|
312
358
|
function clamp(num, min, max, options) {
|
|
@@ -326,6 +372,96 @@ See the Mulan PSL v2 for more details.
|
|
|
326
372
|
return num < min ? defaultMin : num > max ? defaultMax : num;
|
|
327
373
|
}
|
|
328
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
|
+
|
|
407
|
+
function sleep(time = 1000) {
|
|
408
|
+
return new Promise((res) => {
|
|
409
|
+
setTimeout(res, time);
|
|
410
|
+
});
|
|
411
|
+
}
|
|
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
|
+
|
|
452
|
+
const noop = function noop() { };
|
|
453
|
+
|
|
454
|
+
function withResolvers(PromiseLike = Promise) {
|
|
455
|
+
let promise;
|
|
456
|
+
let resolve = noop;
|
|
457
|
+
let reject = noop;
|
|
458
|
+
promise = new PromiseLike((res, rej) => {
|
|
459
|
+
resolve = res;
|
|
460
|
+
reject = rej;
|
|
461
|
+
});
|
|
462
|
+
return { promise, resolve, reject };
|
|
463
|
+
}
|
|
464
|
+
|
|
329
465
|
const mimeMap = {
|
|
330
466
|
application: {
|
|
331
467
|
acrobat: ['pdf'],
|
|
@@ -1325,9 +1461,10 @@ See the Mulan PSL v2 for more details.
|
|
|
1325
1461
|
}
|
|
1326
1462
|
|
|
1327
1463
|
function _throttle(fn, delay, options) {
|
|
1328
|
-
var _a, _b;
|
|
1464
|
+
var _a, _b, _c;
|
|
1329
1465
|
const trailing = (_a = options === null || options === void 0 ? void 0 : options.trailing) !== null && _a !== void 0 ? _a : false;
|
|
1330
|
-
const
|
|
1466
|
+
const trailingRunLast = (_b = options === null || options === void 0 ? void 0 : options.trailingRunLast) !== null && _b !== void 0 ? _b : true;
|
|
1467
|
+
const leading = (_c = options === null || options === void 0 ? void 0 : options.leading) !== null && _c !== void 0 ? _c : true;
|
|
1331
1468
|
let timer = null;
|
|
1332
1469
|
let lastTime = 0;
|
|
1333
1470
|
const clearTimer = () => {
|
|
@@ -1347,6 +1484,9 @@ See the Mulan PSL v2 for more details.
|
|
|
1347
1484
|
lastTime = now;
|
|
1348
1485
|
clearTimer();
|
|
1349
1486
|
}
|
|
1487
|
+
if (timeGap < 0 && trailing && trailingRunLast && timer) {
|
|
1488
|
+
clearTimer();
|
|
1489
|
+
}
|
|
1350
1490
|
if (timeGap >= 0 && leading) {
|
|
1351
1491
|
fn.apply(this, args);
|
|
1352
1492
|
}
|
|
@@ -1364,7 +1504,7 @@ See the Mulan PSL v2 for more details.
|
|
|
1364
1504
|
if (!isNumber(delay) || !isFinite(delay) || delay <= 0) {
|
|
1365
1505
|
throw new Error('Invalid delay parameter');
|
|
1366
1506
|
}
|
|
1367
|
-
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false }, options));
|
|
1507
|
+
return _throttle(fn, delay, Object.assign({ trailing: true, leading: false, trailingRunLast: true }, options));
|
|
1368
1508
|
}
|
|
1369
1509
|
|
|
1370
1510
|
function _cloneArray(obj, map, cloner, ...args) {
|
|
@@ -1652,6 +1792,7 @@ See the Mulan PSL v2 for more details.
|
|
|
1652
1792
|
exports.curry = _curryMore;
|
|
1653
1793
|
exports.debounce = debounce;
|
|
1654
1794
|
exports.deepClone = deepClone;
|
|
1795
|
+
exports.defer = defer;
|
|
1655
1796
|
exports.fastClone = fastClone;
|
|
1656
1797
|
exports.getAcceptableExtByMIME = getAcceptableExtByMIME;
|
|
1657
1798
|
exports.getAcceptableMIMEByExt = getAcceptableMIMEByExt;
|
|
@@ -1709,6 +1850,7 @@ See the Mulan PSL v2 for more details.
|
|
|
1709
1850
|
exports.memo = memo;
|
|
1710
1851
|
exports.noop = noop;
|
|
1711
1852
|
exports.not = not;
|
|
1853
|
+
exports.parallel = parallel;
|
|
1712
1854
|
exports.pascalCase = pascalCase;
|
|
1713
1855
|
exports.pass = pass;
|
|
1714
1856
|
exports.passWith = passWith;
|
|
@@ -1721,6 +1863,7 @@ See the Mulan PSL v2 for more details.
|
|
|
1721
1863
|
exports.randomString = randomString;
|
|
1722
1864
|
exports.range = range;
|
|
1723
1865
|
exports.remove = remove;
|
|
1866
|
+
exports.retry = retry;
|
|
1724
1867
|
exports.shuffle = shuffle;
|
|
1725
1868
|
exports.sleep = sleep;
|
|
1726
1869
|
exports.snakeCase = snakeCase;
|