@naturalcycles/js-lib 14.79.0 → 14.82.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/decorators/retry.decorator.js +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.js +2 -2
- package/dist/json-schema/jsonSchemaBuilder.d.ts +2 -2
- package/dist/json-schema/jsonSchemaBuilder.js +4 -4
- package/dist/json-schema/jsonSchemas.d.ts +2 -2
- package/dist/promise/AggregatedError.d.ts +1 -1
- package/dist/promise/AggregatedError.js +2 -7
- package/dist/promise/pFilter.d.ts +2 -3
- package/dist/promise/pFilter.js +4 -4
- package/dist/promise/pMap.d.ts +1 -1
- package/dist/promise/pMap.js +67 -19
- package/dist/promise/pRetry.d.ts +17 -2
- package/dist/promise/pRetry.js +72 -40
- package/dist/types.d.ts +10 -10
- package/dist-esm/decorators/retry.decorator.js +2 -2
- package/dist-esm/index.js +2 -3
- package/dist-esm/json-schema/jsonSchemaBuilder.js +4 -4
- package/dist-esm/promise/AggregatedError.js +2 -7
- package/dist-esm/promise/pFilter.js +4 -4
- package/dist-esm/promise/pMap.js +79 -19
- package/dist-esm/promise/pRetry.js +70 -39
- package/package.json +1 -1
- package/src/decorators/retry.decorator.ts +2 -2
- package/src/index.ts +2 -2
- package/src/json-schema/jsonSchemaBuilder.ts +4 -4
- package/src/promise/AggregatedError.ts +3 -8
- package/src/promise/pFilter.ts +5 -14
- package/src/promise/pMap.ts +72 -21
- package/src/promise/pRetry.ts +105 -41
- package/src/types.ts +10 -10
- package/dist/promise/pBatch.d.ts +0 -7
- package/dist/promise/pBatch.js +0 -30
- package/dist-esm/promise/pBatch.js +0 -23
- package/src/promise/pBatch.ts +0 -31
package/dist-esm/promise/pMap.js
CHANGED
|
@@ -6,6 +6,7 @@ Improvements:
|
|
|
6
6
|
- Included Typescript typings (no need for @types/p-map)
|
|
7
7
|
- Compatible with pProps (that had typings issues)
|
|
8
8
|
*/
|
|
9
|
+
import { __asyncValues } from "tslib";
|
|
9
10
|
import { END, ErrorMode, SKIP } from '..';
|
|
10
11
|
import { AggregatedError } from './AggregatedError';
|
|
11
12
|
/**
|
|
@@ -35,28 +36,85 @@ import { AggregatedError } from './AggregatedError';
|
|
|
35
36
|
* })();
|
|
36
37
|
*/
|
|
37
38
|
export async function pMap(iterable, mapper, opt = {}) {
|
|
39
|
+
var e_1, _a;
|
|
40
|
+
const ret = [];
|
|
41
|
+
// const iterator = iterable[Symbol.iterator]()
|
|
42
|
+
const items = [...iterable];
|
|
43
|
+
const itemsLength = items.length;
|
|
44
|
+
if (itemsLength === 0)
|
|
45
|
+
return []; // short circuit
|
|
46
|
+
const { concurrency = itemsLength, errorMode = ErrorMode.THROW_IMMEDIATELY } = opt;
|
|
47
|
+
const errors = [];
|
|
48
|
+
let isSettled = false;
|
|
49
|
+
let resolvingCount = 0;
|
|
50
|
+
let currentIndex = 0;
|
|
51
|
+
// Special cases that are able to preserve async stack traces
|
|
52
|
+
if (concurrency === 1) {
|
|
53
|
+
try {
|
|
54
|
+
// Special case for concurrency == 1
|
|
55
|
+
for (var items_1 = __asyncValues(items), items_1_1; items_1_1 = await items_1.next(), !items_1_1.done;) {
|
|
56
|
+
const item = items_1_1.value;
|
|
57
|
+
try {
|
|
58
|
+
const r = await mapper(item, currentIndex++);
|
|
59
|
+
if (r === END)
|
|
60
|
+
break;
|
|
61
|
+
if (r !== SKIP)
|
|
62
|
+
ret.push(r);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY)
|
|
66
|
+
throw err;
|
|
67
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
68
|
+
errors.push(err);
|
|
69
|
+
}
|
|
70
|
+
// otherwise, suppress completely
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
75
|
+
finally {
|
|
76
|
+
try {
|
|
77
|
+
if (items_1_1 && !items_1_1.done && (_a = items_1.return)) await _a.call(items_1);
|
|
78
|
+
}
|
|
79
|
+
finally { if (e_1) throw e_1.error; }
|
|
80
|
+
}
|
|
81
|
+
if (errors.length) {
|
|
82
|
+
throw new AggregatedError(errors, ret);
|
|
83
|
+
}
|
|
84
|
+
return ret;
|
|
85
|
+
}
|
|
86
|
+
else if (!opt.concurrency || items.length <= opt.concurrency) {
|
|
87
|
+
// Special case for concurrency == infinity or iterable.length < concurrency
|
|
88
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
89
|
+
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== SKIP && r !== END);
|
|
90
|
+
}
|
|
91
|
+
;
|
|
92
|
+
(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
|
|
93
|
+
if (r.status === 'fulfilled') {
|
|
94
|
+
if (r.value !== SKIP && r.value !== END)
|
|
95
|
+
ret.push(r.value);
|
|
96
|
+
}
|
|
97
|
+
else if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
98
|
+
errors.push(r.reason);
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
if (errors.length) {
|
|
102
|
+
throw new AggregatedError(errors, ret);
|
|
103
|
+
}
|
|
104
|
+
return ret;
|
|
105
|
+
}
|
|
38
106
|
return new Promise((resolve, reject) => {
|
|
39
|
-
const
|
|
40
|
-
const ret = [];
|
|
41
|
-
const iterator = iterable[Symbol.iterator]();
|
|
42
|
-
const errors = [];
|
|
43
|
-
let isSettled = false;
|
|
44
|
-
let isIterableDone = false;
|
|
45
|
-
let resolvingCount = 0;
|
|
46
|
-
let currentIndex = 0;
|
|
47
|
-
const next = (skipped = false) => {
|
|
107
|
+
const next = () => {
|
|
48
108
|
if (isSettled) {
|
|
49
109
|
return;
|
|
50
110
|
}
|
|
51
|
-
const nextItem =
|
|
52
|
-
const i = currentIndex
|
|
53
|
-
if (
|
|
54
|
-
currentIndex++;
|
|
55
|
-
if (nextItem.done) {
|
|
56
|
-
isIterableDone = true;
|
|
111
|
+
const nextItem = items[currentIndex];
|
|
112
|
+
const i = currentIndex++;
|
|
113
|
+
if (currentIndex > itemsLength) {
|
|
57
114
|
if (resolvingCount === 0) {
|
|
115
|
+
isSettled = true;
|
|
58
116
|
const r = ret.filter(r => r !== SKIP);
|
|
59
|
-
if (errors.length
|
|
117
|
+
if (errors.length) {
|
|
60
118
|
reject(new AggregatedError(errors, r));
|
|
61
119
|
}
|
|
62
120
|
else {
|
|
@@ -66,7 +124,7 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
66
124
|
return;
|
|
67
125
|
}
|
|
68
126
|
resolvingCount++;
|
|
69
|
-
Promise.resolve(nextItem
|
|
127
|
+
Promise.resolve(nextItem)
|
|
70
128
|
.then(async (element) => await mapper(element, i))
|
|
71
129
|
.then(value => {
|
|
72
130
|
if (value === END) {
|
|
@@ -82,7 +140,9 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
82
140
|
reject(err);
|
|
83
141
|
}
|
|
84
142
|
else {
|
|
85
|
-
|
|
143
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
144
|
+
errors.push(err);
|
|
145
|
+
}
|
|
86
146
|
resolvingCount--;
|
|
87
147
|
next();
|
|
88
148
|
}
|
|
@@ -90,7 +150,7 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
90
150
|
};
|
|
91
151
|
for (let i = 0; i < concurrency; i++) {
|
|
92
152
|
next();
|
|
93
|
-
if (
|
|
153
|
+
if (isSettled) {
|
|
94
154
|
break;
|
|
95
155
|
}
|
|
96
156
|
}
|
|
@@ -1,54 +1,85 @@
|
|
|
1
1
|
import { _since, _stringifyAny } from '..';
|
|
2
|
+
import { TimeoutError } from './pTimeout';
|
|
2
3
|
/**
|
|
3
4
|
* Returns a Function (!), enhanced with retry capabilities.
|
|
4
5
|
* Implements "Exponential back-off strategy" by multiplying the delay by `delayMultiplier` with each try.
|
|
5
6
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
export function pRetryFn(fn, opt = {}) {
|
|
8
|
+
return async function pRetryFunction(...args) {
|
|
9
|
+
return await pRetry(() => fn.call(this, ...args), opt);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
export async function pRetry(fn, opt = {}) {
|
|
13
|
+
const { maxAttempts = 4, delay: initialDelay = 1000, delayMultiplier = 2, predicate, logger = console, name, keepStackTrace = true, timeout, } = opt;
|
|
14
|
+
const fakeError = keepStackTrace ? new Error('RetryError') : undefined;
|
|
9
15
|
let { logFirstAttempt = false, logRetries = true, logFailures = false, logSuccess = false } = opt;
|
|
10
16
|
if (opt.logAll) {
|
|
11
|
-
logFirstAttempt = logRetries = logFailures = true;
|
|
17
|
+
logSuccess = logFirstAttempt = logRetries = logFailures = true;
|
|
12
18
|
}
|
|
13
19
|
if (opt.logNone) {
|
|
14
20
|
logSuccess = logFirstAttempt = logRetries = logFailures = false;
|
|
15
21
|
}
|
|
16
|
-
const fname =
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
22
|
+
const fname = name || fn.name || 'pRetry function';
|
|
23
|
+
let delay = initialDelay;
|
|
24
|
+
let attempt = 0;
|
|
25
|
+
let timer;
|
|
26
|
+
let timedOut = false;
|
|
27
|
+
return await new Promise((resolve, reject) => {
|
|
28
|
+
const rejectWithTimeout = () => {
|
|
29
|
+
timedOut = true; // to prevent more tries
|
|
30
|
+
const err = new TimeoutError(`"${fname}" timed out after ${timeout} ms`);
|
|
31
|
+
if (fakeError) {
|
|
32
|
+
// keep original stack
|
|
33
|
+
err.stack = fakeError.stack.replace('Error: RetryError', 'TimeoutError');
|
|
34
|
+
}
|
|
35
|
+
reject(err);
|
|
36
|
+
};
|
|
37
|
+
const next = async () => {
|
|
38
|
+
if (timedOut)
|
|
39
|
+
return;
|
|
40
|
+
if (timeout) {
|
|
41
|
+
timer = setTimeout(rejectWithTimeout, timeout);
|
|
42
|
+
}
|
|
43
|
+
const started = Date.now();
|
|
44
|
+
try {
|
|
45
|
+
attempt++;
|
|
46
|
+
if ((attempt === 1 && logFirstAttempt) || (attempt > 1 && logRetries)) {
|
|
47
|
+
logger.log(`${fname} attempt #${attempt}...`);
|
|
33
48
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
49
|
+
const r = await fn(attempt);
|
|
50
|
+
clearTimeout(timer);
|
|
51
|
+
if (logSuccess) {
|
|
52
|
+
logger.log(`${fname} attempt #${attempt} succeeded in ${_since(started)}`);
|
|
53
|
+
}
|
|
54
|
+
resolve(r);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
clearTimeout(timer);
|
|
58
|
+
if (logFailures) {
|
|
59
|
+
logger.warn(`${fname} attempt #${attempt} error in ${_since(started)}:`, _stringifyAny(err, {
|
|
60
|
+
includeErrorData: true,
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
if (attempt >= maxAttempts ||
|
|
64
|
+
(predicate && !predicate(err, attempt, maxAttempts))) {
|
|
65
|
+
// Give up
|
|
66
|
+
if (fakeError) {
|
|
67
|
+
// Preserve the original call stack
|
|
68
|
+
Object.defineProperty(err, 'stack', {
|
|
69
|
+
value: err.stack +
|
|
70
|
+
'\n --' +
|
|
71
|
+
fakeError.stack.replace('Error: RetryError', ''),
|
|
72
|
+
});
|
|
48
73
|
}
|
|
74
|
+
reject(err);
|
|
49
75
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
76
|
+
else {
|
|
77
|
+
// Retry after delay
|
|
78
|
+
delay *= delayMultiplier;
|
|
79
|
+
setTimeout(next, delay);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
void next();
|
|
84
|
+
});
|
|
54
85
|
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { pRetryFn, PRetryOptions } from '..'
|
|
2
2
|
|
|
3
3
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
4
4
|
export function _Retry(opt: PRetryOptions = {}): MethodDecorator {
|
|
5
5
|
return (target, key, descriptor) => {
|
|
6
6
|
const originalFn = descriptor.value
|
|
7
|
-
descriptor.value =
|
|
7
|
+
descriptor.value = pRetryFn(originalFn as any, opt)
|
|
8
8
|
return descriptor
|
|
9
9
|
}
|
|
10
10
|
}
|
package/src/index.ts
CHANGED
|
@@ -67,14 +67,13 @@ export * from './object/object.util'
|
|
|
67
67
|
export * from './object/sortObject'
|
|
68
68
|
export * from './object/sortObjectDeep'
|
|
69
69
|
import { AggregatedError } from './promise/AggregatedError'
|
|
70
|
-
export * from './promise/pBatch'
|
|
71
70
|
import { DeferredPromise, pDefer } from './promise/pDefer'
|
|
72
71
|
export * from './promise/pDelay'
|
|
73
72
|
export * from './promise/pFilter'
|
|
74
73
|
export * from './promise/pHang'
|
|
75
74
|
import { pMap, PMapOptions } from './promise/pMap'
|
|
76
75
|
export * from './promise/pProps'
|
|
77
|
-
import { pRetry, PRetryOptions } from './promise/pRetry'
|
|
76
|
+
import { pRetry, pRetryFn, PRetryOptions } from './promise/pRetry'
|
|
78
77
|
export * from './promise/pState'
|
|
79
78
|
import { pTimeout, pTimeoutFn, PTimeoutOptions } from './promise/pTimeout'
|
|
80
79
|
export * from './promise/pTuple'
|
|
@@ -250,6 +249,7 @@ export {
|
|
|
250
249
|
pDefer,
|
|
251
250
|
AggregatedError,
|
|
252
251
|
pRetry,
|
|
252
|
+
pRetryFn,
|
|
253
253
|
pTimeout,
|
|
254
254
|
pTimeoutFn,
|
|
255
255
|
_tryCatch,
|
|
@@ -365,9 +365,9 @@ export class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyB
|
|
|
365
365
|
return this
|
|
366
366
|
}
|
|
367
367
|
|
|
368
|
-
baseDBEntity(): JsonSchemaObjectBuilder<T & BaseDBEntity
|
|
368
|
+
baseDBEntity<ID = string>(idType = 'string'): JsonSchemaObjectBuilder<T & BaseDBEntity<ID>> {
|
|
369
369
|
Object.assign(this.schema.properties, {
|
|
370
|
-
id: { type:
|
|
370
|
+
id: { type: idType },
|
|
371
371
|
created: { type: 'number', format: 'unixTimestamp' },
|
|
372
372
|
updated: { type: 'number', format: 'unixTimestamp' },
|
|
373
373
|
})
|
|
@@ -375,8 +375,8 @@ export class JsonSchemaObjectBuilder<T extends AnyObject> extends JsonSchemaAnyB
|
|
|
375
375
|
return this
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
-
savedDBEntity(): JsonSchemaObjectBuilder<T & SavedDBEntity
|
|
379
|
-
return this.baseDBEntity().addRequired(['id', 'created', 'updated']) as any
|
|
378
|
+
savedDBEntity<ID = string>(idType = 'string'): JsonSchemaObjectBuilder<T & SavedDBEntity<ID>> {
|
|
379
|
+
return this.baseDBEntity(idType).addRequired(['id', 'created', 'updated']) as any
|
|
380
380
|
}
|
|
381
381
|
|
|
382
382
|
extend<T2 extends AnyObject>(s2: JsonSchemaObjectBuilder<T2>): JsonSchemaObjectBuilder<T & T2> {
|
|
@@ -7,20 +7,15 @@ export class AggregatedError<RESULT = any> extends Error {
|
|
|
7
7
|
errors!: Error[]
|
|
8
8
|
results!: RESULT[]
|
|
9
9
|
|
|
10
|
-
constructor(errors:
|
|
11
|
-
const mappedErrors = errors.map(e => {
|
|
12
|
-
if (typeof e === 'string') return new Error(e)
|
|
13
|
-
return e
|
|
14
|
-
})
|
|
15
|
-
|
|
10
|
+
constructor(errors: Error[], results: RESULT[] = []) {
|
|
16
11
|
const message = [
|
|
17
12
|
`${errors.length} errors:`,
|
|
18
|
-
...
|
|
13
|
+
...errors.map((e, i) => `${i + 1}. ${e.message}`),
|
|
19
14
|
].join('\n')
|
|
20
15
|
|
|
21
16
|
super(message)
|
|
22
17
|
|
|
23
|
-
this.errors =
|
|
18
|
+
this.errors = errors
|
|
24
19
|
this.results = results
|
|
25
20
|
|
|
26
21
|
Object.defineProperty(this, 'name', {
|
package/src/promise/pFilter.ts
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { pMap, PMapOptions } from './pMap'
|
|
1
|
+
import { AsyncPredicate } from '../types'
|
|
3
2
|
|
|
4
|
-
export async function pFilter<T>(
|
|
5
|
-
|
|
6
|
-
filterFn
|
|
7
|
-
|
|
8
|
-
): Promise<T[]> {
|
|
9
|
-
const values = await pMap(
|
|
10
|
-
iterable,
|
|
11
|
-
async (item, index) => await Promise.all([filterFn(item, index), item]),
|
|
12
|
-
opt,
|
|
13
|
-
)
|
|
14
|
-
|
|
15
|
-
return values.filter(value => Boolean(value[0])).map(value => value[1])
|
|
3
|
+
export async function pFilter<T>(iterable: Iterable<T>, filterFn: AsyncPredicate<T>): Promise<T[]> {
|
|
4
|
+
const items = [...iterable]
|
|
5
|
+
const predicates = await Promise.all(items.map((item, i) => filterFn(item, i)))
|
|
6
|
+
return items.filter((item, i) => predicates[i])
|
|
16
7
|
}
|
package/src/promise/pMap.ts
CHANGED
|
@@ -55,36 +55,85 @@ export interface PMapOptions {
|
|
|
55
55
|
* })();
|
|
56
56
|
*/
|
|
57
57
|
export async function pMap<IN, OUT>(
|
|
58
|
-
iterable: Iterable<IN
|
|
58
|
+
iterable: Iterable<IN>,
|
|
59
59
|
mapper: AbortableAsyncMapper<IN, OUT>,
|
|
60
60
|
opt: PMapOptions = {},
|
|
61
61
|
): Promise<OUT[]> {
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
const ret: (OUT | typeof SKIP)[] = []
|
|
63
|
+
// const iterator = iterable[Symbol.iterator]()
|
|
64
|
+
const items = [...iterable]
|
|
65
|
+
const itemsLength = items.length
|
|
66
|
+
if (itemsLength === 0) return [] // short circuit
|
|
67
|
+
|
|
68
|
+
const { concurrency = itemsLength, errorMode = ErrorMode.THROW_IMMEDIATELY } = opt
|
|
69
|
+
|
|
70
|
+
const errors: Error[] = []
|
|
71
|
+
let isSettled = false
|
|
72
|
+
let resolvingCount = 0
|
|
73
|
+
let currentIndex = 0
|
|
74
|
+
|
|
75
|
+
// Special cases that are able to preserve async stack traces
|
|
76
|
+
|
|
77
|
+
if (concurrency === 1) {
|
|
78
|
+
// Special case for concurrency == 1
|
|
79
|
+
|
|
80
|
+
for await (const item of items) {
|
|
81
|
+
try {
|
|
82
|
+
const r = await mapper(item, currentIndex++)
|
|
83
|
+
if (r === END) break
|
|
84
|
+
if (r !== SKIP) ret.push(r)
|
|
85
|
+
} catch (err) {
|
|
86
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) throw err
|
|
87
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
88
|
+
errors.push(err as Error)
|
|
89
|
+
}
|
|
90
|
+
// otherwise, suppress completely
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (errors.length) {
|
|
95
|
+
throw new AggregatedError(errors, ret)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return ret as OUT[]
|
|
99
|
+
} else if (!opt.concurrency || items.length <= opt.concurrency) {
|
|
100
|
+
// Special case for concurrency == infinity or iterable.length < concurrency
|
|
101
|
+
|
|
102
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
103
|
+
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(
|
|
104
|
+
r => r !== SKIP && r !== END,
|
|
105
|
+
) as OUT[]
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
;(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
|
|
109
|
+
if (r.status === 'fulfilled') {
|
|
110
|
+
if (r.value !== SKIP && r.value !== END) ret.push(r.value)
|
|
111
|
+
} else if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
112
|
+
errors.push(r.reason)
|
|
113
|
+
}
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
if (errors.length) {
|
|
117
|
+
throw new AggregatedError(errors, ret)
|
|
118
|
+
}
|
|
64
119
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const errors: Error[] = []
|
|
68
|
-
let isSettled = false
|
|
69
|
-
let isIterableDone = false
|
|
70
|
-
let resolvingCount = 0
|
|
71
|
-
let currentIndex = 0
|
|
120
|
+
return ret as OUT[]
|
|
121
|
+
}
|
|
72
122
|
|
|
73
|
-
|
|
123
|
+
return new Promise<OUT[]>((resolve, reject) => {
|
|
124
|
+
const next = () => {
|
|
74
125
|
if (isSettled) {
|
|
75
126
|
return
|
|
76
127
|
}
|
|
77
128
|
|
|
78
|
-
const nextItem =
|
|
79
|
-
const i = currentIndex
|
|
80
|
-
if (!skipped) currentIndex++
|
|
81
|
-
|
|
82
|
-
if (nextItem.done) {
|
|
83
|
-
isIterableDone = true
|
|
129
|
+
const nextItem = items[currentIndex]!
|
|
130
|
+
const i = currentIndex++
|
|
84
131
|
|
|
132
|
+
if (currentIndex > itemsLength) {
|
|
85
133
|
if (resolvingCount === 0) {
|
|
134
|
+
isSettled = true
|
|
86
135
|
const r = ret.filter(r => r !== SKIP) as OUT[]
|
|
87
|
-
if (errors.length
|
|
136
|
+
if (errors.length) {
|
|
88
137
|
reject(new AggregatedError(errors, r))
|
|
89
138
|
} else {
|
|
90
139
|
resolve(r)
|
|
@@ -96,7 +145,7 @@ export async function pMap<IN, OUT>(
|
|
|
96
145
|
|
|
97
146
|
resolvingCount++
|
|
98
147
|
|
|
99
|
-
Promise.resolve(nextItem
|
|
148
|
+
Promise.resolve(nextItem)
|
|
100
149
|
.then(async element => await mapper(element, i))
|
|
101
150
|
.then(
|
|
102
151
|
value => {
|
|
@@ -114,7 +163,9 @@ export async function pMap<IN, OUT>(
|
|
|
114
163
|
isSettled = true
|
|
115
164
|
reject(err)
|
|
116
165
|
} else {
|
|
117
|
-
|
|
166
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
167
|
+
errors.push(err)
|
|
168
|
+
}
|
|
118
169
|
resolvingCount--
|
|
119
170
|
next()
|
|
120
171
|
}
|
|
@@ -125,7 +176,7 @@ export async function pMap<IN, OUT>(
|
|
|
125
176
|
for (let i = 0; i < concurrency; i++) {
|
|
126
177
|
next()
|
|
127
178
|
|
|
128
|
-
if (
|
|
179
|
+
if (isSettled) {
|
|
129
180
|
break
|
|
130
181
|
}
|
|
131
182
|
}
|