@naturalcycles/js-lib 14.218.0 → 14.219.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/promise/pMap.d.ts +13 -1
- package/dist/promise/pMap.js +81 -64
- package/dist-esm/promise/pMap.js +81 -64
- package/package.json +1 -1
- package/src/promise/pMap.ts +100 -67
package/dist/promise/pMap.d.ts
CHANGED
|
@@ -4,7 +4,11 @@ export interface PMapOptions {
|
|
|
4
4
|
/**
|
|
5
5
|
* Number of concurrently pending promises returned by `mapper`.
|
|
6
6
|
*
|
|
7
|
-
*
|
|
7
|
+
* Defaults to 16.
|
|
8
|
+
*
|
|
9
|
+
* It previously (and originally) defaulted to Infinity, which was later changed,
|
|
10
|
+
* because it's somewhat dangerous to run "infinite number of parallel promises".
|
|
11
|
+
* You can still emulate the old behavior by passing `Infinity`.
|
|
8
12
|
*/
|
|
9
13
|
concurrency?: number;
|
|
10
14
|
/**
|
|
@@ -23,6 +27,14 @@ export interface PMapOptions {
|
|
|
23
27
|
logger?: CommonLogger | null;
|
|
24
28
|
}
|
|
25
29
|
/**
|
|
30
|
+
* Forked from https://github.com/sindresorhus/p-map
|
|
31
|
+
*
|
|
32
|
+
* Improvements:
|
|
33
|
+
* - Exported as { pMap }, so IDE auto-completion works
|
|
34
|
+
* - Included Typescript typings (no need for @types/p-map)
|
|
35
|
+
* - Compatible with pProps (that had typings issues)
|
|
36
|
+
* - Preserves async stack traces (in selected cases)
|
|
37
|
+
*
|
|
26
38
|
* Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
|
|
27
39
|
* or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
|
|
28
40
|
* from `mapper` in `input` order.
|
package/dist/promise/pMap.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
Taken from https://github.com/sindresorhus/p-map
|
|
4
|
-
|
|
5
|
-
Improvements:
|
|
6
|
-
- Exported as { pMap }, so IDE auto-completion works
|
|
7
|
-
- Included Typescript typings (no need for @types/p-map)
|
|
8
|
-
- Compatible with pProps (that had typings issues)
|
|
9
|
-
*/
|
|
10
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
3
|
exports.pMap = void 0;
|
|
12
4
|
const __1 = require("..");
|
|
13
5
|
/**
|
|
6
|
+
* Forked from https://github.com/sindresorhus/p-map
|
|
7
|
+
*
|
|
8
|
+
* Improvements:
|
|
9
|
+
* - Exported as { pMap }, so IDE auto-completion works
|
|
10
|
+
* - Included Typescript typings (no need for @types/p-map)
|
|
11
|
+
* - Compatible with pProps (that had typings issues)
|
|
12
|
+
* - Preserves async stack traces (in selected cases)
|
|
13
|
+
*
|
|
14
14
|
* Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
|
|
15
15
|
* or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
|
|
16
16
|
* from `mapper` in `input` order.
|
|
@@ -37,70 +37,26 @@ const __1 = require("..");
|
|
|
37
37
|
* })();
|
|
38
38
|
*/
|
|
39
39
|
async function pMap(iterable, mapper, opt = {}) {
|
|
40
|
-
const { logger = console } = opt;
|
|
41
|
-
const ret = [];
|
|
42
|
-
// const iterator = iterable[Symbol.iterator]()
|
|
43
40
|
const items = [...iterable];
|
|
44
41
|
const itemsLength = items.length;
|
|
45
42
|
if (itemsLength === 0)
|
|
46
43
|
return []; // short circuit
|
|
47
|
-
const { concurrency =
|
|
48
|
-
const errors = [];
|
|
49
|
-
let isSettled = false;
|
|
50
|
-
let resolvingCount = 0;
|
|
51
|
-
let currentIndex = 0;
|
|
44
|
+
const { concurrency = 16, errorMode = __1.ErrorMode.THROW_IMMEDIATELY, logger = console } = opt;
|
|
52
45
|
// Special cases that are able to preserve async stack traces
|
|
46
|
+
// Special case: serial execution
|
|
53
47
|
if (concurrency === 1) {
|
|
54
|
-
|
|
55
|
-
for (const item of items) {
|
|
56
|
-
try {
|
|
57
|
-
const r = await mapper(item, currentIndex++);
|
|
58
|
-
if (r === __1.END)
|
|
59
|
-
break;
|
|
60
|
-
if (r !== __1.SKIP)
|
|
61
|
-
ret.push(r);
|
|
62
|
-
}
|
|
63
|
-
catch (err) {
|
|
64
|
-
if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY)
|
|
65
|
-
throw err;
|
|
66
|
-
if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
|
|
67
|
-
errors.push(err);
|
|
68
|
-
}
|
|
69
|
-
else {
|
|
70
|
-
// otherwise, suppress (but still log via logger)
|
|
71
|
-
logger?.error(err);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
if (errors.length) {
|
|
76
|
-
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
77
|
-
}
|
|
78
|
-
return ret;
|
|
48
|
+
return await pMap1(items, mapper, errorMode, logger);
|
|
79
49
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== __1.SKIP && r !== __1.END);
|
|
84
|
-
}
|
|
85
|
-
;
|
|
86
|
-
(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
|
|
87
|
-
if (r.status === 'fulfilled') {
|
|
88
|
-
if (r.value !== __1.SKIP && r.value !== __1.END)
|
|
89
|
-
ret.push(r.value);
|
|
90
|
-
}
|
|
91
|
-
else if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
|
|
92
|
-
errors.push(r.reason);
|
|
93
|
-
}
|
|
94
|
-
else {
|
|
95
|
-
// otherwise, suppress (but still log via logger)
|
|
96
|
-
logger?.error(r.reason);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
if (errors.length) {
|
|
100
|
-
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
101
|
-
}
|
|
102
|
-
return ret;
|
|
50
|
+
// Special case: concurrency === Infinity or items.length <= concurrency
|
|
51
|
+
if (concurrency === Infinity || items.length <= concurrency) {
|
|
52
|
+
return await pMapAll(items, mapper, errorMode, logger);
|
|
103
53
|
}
|
|
54
|
+
// General case: execution with throttled concurrency
|
|
55
|
+
const ret = [];
|
|
56
|
+
const errors = [];
|
|
57
|
+
let isSettled = false;
|
|
58
|
+
let resolvingCount = 0;
|
|
59
|
+
let currentIndex = 0;
|
|
104
60
|
return await new Promise((resolve, reject) => {
|
|
105
61
|
const next = () => {
|
|
106
62
|
if (isSettled) {
|
|
@@ -159,3 +115,64 @@ async function pMap(iterable, mapper, opt = {}) {
|
|
|
159
115
|
});
|
|
160
116
|
}
|
|
161
117
|
exports.pMap = pMap;
|
|
118
|
+
/**
|
|
119
|
+
pMap with serial (non-concurrent) execution.
|
|
120
|
+
*/
|
|
121
|
+
async function pMap1(items, mapper, errorMode, logger) {
|
|
122
|
+
let i = 0;
|
|
123
|
+
const ret = [];
|
|
124
|
+
const errors = [];
|
|
125
|
+
for (const item of items) {
|
|
126
|
+
try {
|
|
127
|
+
const r = await mapper(item, i++);
|
|
128
|
+
if (r === __1.END)
|
|
129
|
+
break;
|
|
130
|
+
if (r !== __1.SKIP)
|
|
131
|
+
ret.push(r);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY)
|
|
135
|
+
throw err;
|
|
136
|
+
if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
|
|
137
|
+
errors.push(err);
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
// otherwise, suppress (but still log via logger)
|
|
141
|
+
logger?.error(err);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (errors.length) {
|
|
146
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
147
|
+
}
|
|
148
|
+
return ret;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
pMap with fully concurrent execution, like Promise.all
|
|
152
|
+
*/
|
|
153
|
+
async function pMapAll(items, mapper, errorMode, logger) {
|
|
154
|
+
if (errorMode === __1.ErrorMode.THROW_IMMEDIATELY) {
|
|
155
|
+
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== __1.SKIP && r !== __1.END);
|
|
156
|
+
}
|
|
157
|
+
const ret = [];
|
|
158
|
+
const errors = [];
|
|
159
|
+
for (const r of await Promise.allSettled(items.map((item, i) => mapper(item, i)))) {
|
|
160
|
+
if (r.status === 'fulfilled') {
|
|
161
|
+
if (r.value === __1.END)
|
|
162
|
+
break;
|
|
163
|
+
if (r.value !== __1.SKIP)
|
|
164
|
+
ret.push(r.value);
|
|
165
|
+
}
|
|
166
|
+
else if (errorMode === __1.ErrorMode.THROW_AGGREGATED) {
|
|
167
|
+
errors.push(r.reason);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
// otherwise, suppress (but still log via logger)
|
|
171
|
+
logger?.error(r.reason);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (errors.length) {
|
|
175
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
176
|
+
}
|
|
177
|
+
return ret;
|
|
178
|
+
}
|
package/dist-esm/promise/pMap.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Taken from https://github.com/sindresorhus/p-map
|
|
3
|
-
|
|
4
|
-
Improvements:
|
|
5
|
-
- Exported as { pMap }, so IDE auto-completion works
|
|
6
|
-
- Included Typescript typings (no need for @types/p-map)
|
|
7
|
-
- Compatible with pProps (that had typings issues)
|
|
8
|
-
*/
|
|
9
1
|
import { END, ErrorMode, SKIP } from '..';
|
|
10
2
|
/**
|
|
3
|
+
* Forked from https://github.com/sindresorhus/p-map
|
|
4
|
+
*
|
|
5
|
+
* Improvements:
|
|
6
|
+
* - Exported as { pMap }, so IDE auto-completion works
|
|
7
|
+
* - Included Typescript typings (no need for @types/p-map)
|
|
8
|
+
* - Compatible with pProps (that had typings issues)
|
|
9
|
+
* - Preserves async stack traces (in selected cases)
|
|
10
|
+
*
|
|
11
11
|
* Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
|
|
12
12
|
* or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
|
|
13
13
|
* from `mapper` in `input` order.
|
|
@@ -34,70 +34,26 @@ import { END, ErrorMode, SKIP } from '..';
|
|
|
34
34
|
* })();
|
|
35
35
|
*/
|
|
36
36
|
export async function pMap(iterable, mapper, opt = {}) {
|
|
37
|
-
const { logger = console } = opt;
|
|
38
|
-
const ret = [];
|
|
39
|
-
// const iterator = iterable[Symbol.iterator]()
|
|
40
37
|
const items = [...iterable];
|
|
41
38
|
const itemsLength = items.length;
|
|
42
39
|
if (itemsLength === 0)
|
|
43
40
|
return []; // short circuit
|
|
44
|
-
const { concurrency =
|
|
45
|
-
const errors = [];
|
|
46
|
-
let isSettled = false;
|
|
47
|
-
let resolvingCount = 0;
|
|
48
|
-
let currentIndex = 0;
|
|
41
|
+
const { concurrency = 16, errorMode = ErrorMode.THROW_IMMEDIATELY, logger = console } = opt;
|
|
49
42
|
// Special cases that are able to preserve async stack traces
|
|
43
|
+
// Special case: serial execution
|
|
50
44
|
if (concurrency === 1) {
|
|
51
|
-
|
|
52
|
-
for (const item of items) {
|
|
53
|
-
try {
|
|
54
|
-
const r = await mapper(item, currentIndex++);
|
|
55
|
-
if (r === END)
|
|
56
|
-
break;
|
|
57
|
-
if (r !== SKIP)
|
|
58
|
-
ret.push(r);
|
|
59
|
-
}
|
|
60
|
-
catch (err) {
|
|
61
|
-
if (errorMode === ErrorMode.THROW_IMMEDIATELY)
|
|
62
|
-
throw err;
|
|
63
|
-
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
64
|
-
errors.push(err);
|
|
65
|
-
}
|
|
66
|
-
else {
|
|
67
|
-
// otherwise, suppress (but still log via logger)
|
|
68
|
-
logger === null || logger === void 0 ? void 0 : logger.error(err);
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
if (errors.length) {
|
|
73
|
-
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
74
|
-
}
|
|
75
|
-
return ret;
|
|
45
|
+
return await pMap1(items, mapper, errorMode, logger);
|
|
76
46
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== SKIP && r !== END);
|
|
81
|
-
}
|
|
82
|
-
;
|
|
83
|
-
(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
|
|
84
|
-
if (r.status === 'fulfilled') {
|
|
85
|
-
if (r.value !== SKIP && r.value !== END)
|
|
86
|
-
ret.push(r.value);
|
|
87
|
-
}
|
|
88
|
-
else if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
89
|
-
errors.push(r.reason);
|
|
90
|
-
}
|
|
91
|
-
else {
|
|
92
|
-
// otherwise, suppress (but still log via logger)
|
|
93
|
-
logger === null || logger === void 0 ? void 0 : logger.error(r.reason);
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
if (errors.length) {
|
|
97
|
-
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
98
|
-
}
|
|
99
|
-
return ret;
|
|
47
|
+
// Special case: concurrency === Infinity or items.length <= concurrency
|
|
48
|
+
if (concurrency === Infinity || items.length <= concurrency) {
|
|
49
|
+
return await pMapAll(items, mapper, errorMode, logger);
|
|
100
50
|
}
|
|
51
|
+
// General case: execution with throttled concurrency
|
|
52
|
+
const ret = [];
|
|
53
|
+
const errors = [];
|
|
54
|
+
let isSettled = false;
|
|
55
|
+
let resolvingCount = 0;
|
|
56
|
+
let currentIndex = 0;
|
|
101
57
|
return await new Promise((resolve, reject) => {
|
|
102
58
|
const next = () => {
|
|
103
59
|
if (isSettled) {
|
|
@@ -155,3 +111,64 @@ export async function pMap(iterable, mapper, opt = {}) {
|
|
|
155
111
|
}
|
|
156
112
|
});
|
|
157
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
pMap with serial (non-concurrent) execution.
|
|
116
|
+
*/
|
|
117
|
+
async function pMap1(items, mapper, errorMode, logger) {
|
|
118
|
+
let i = 0;
|
|
119
|
+
const ret = [];
|
|
120
|
+
const errors = [];
|
|
121
|
+
for (const item of items) {
|
|
122
|
+
try {
|
|
123
|
+
const r = await mapper(item, i++);
|
|
124
|
+
if (r === END)
|
|
125
|
+
break;
|
|
126
|
+
if (r !== SKIP)
|
|
127
|
+
ret.push(r);
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY)
|
|
131
|
+
throw err;
|
|
132
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
133
|
+
errors.push(err);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// otherwise, suppress (but still log via logger)
|
|
137
|
+
logger === null || logger === void 0 ? void 0 : logger.error(err);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (errors.length) {
|
|
142
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
143
|
+
}
|
|
144
|
+
return ret;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
pMap with fully concurrent execution, like Promise.all
|
|
148
|
+
*/
|
|
149
|
+
async function pMapAll(items, mapper, errorMode, logger) {
|
|
150
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
151
|
+
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(r => r !== SKIP && r !== END);
|
|
152
|
+
}
|
|
153
|
+
const ret = [];
|
|
154
|
+
const errors = [];
|
|
155
|
+
for (const r of await Promise.allSettled(items.map((item, i) => mapper(item, i)))) {
|
|
156
|
+
if (r.status === 'fulfilled') {
|
|
157
|
+
if (r.value === END)
|
|
158
|
+
break;
|
|
159
|
+
if (r.value !== SKIP)
|
|
160
|
+
ret.push(r.value);
|
|
161
|
+
}
|
|
162
|
+
else if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
163
|
+
errors.push(r.reason);
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
// otherwise, suppress (but still log via logger)
|
|
167
|
+
logger === null || logger === void 0 ? void 0 : logger.error(r.reason);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
if (errors.length) {
|
|
171
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`);
|
|
172
|
+
}
|
|
173
|
+
return ret;
|
|
174
|
+
}
|
package/package.json
CHANGED
package/src/promise/pMap.ts
CHANGED
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
/*
|
|
2
|
-
Taken from https://github.com/sindresorhus/p-map
|
|
3
|
-
|
|
4
|
-
Improvements:
|
|
5
|
-
- Exported as { pMap }, so IDE auto-completion works
|
|
6
|
-
- Included Typescript typings (no need for @types/p-map)
|
|
7
|
-
- Compatible with pProps (that had typings issues)
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
1
|
import type { AbortableAsyncMapper, CommonLogger } from '..'
|
|
11
2
|
import { END, ErrorMode, SKIP } from '..'
|
|
12
3
|
|
|
@@ -14,7 +5,11 @@ export interface PMapOptions {
|
|
|
14
5
|
/**
|
|
15
6
|
* Number of concurrently pending promises returned by `mapper`.
|
|
16
7
|
*
|
|
17
|
-
*
|
|
8
|
+
* Defaults to 16.
|
|
9
|
+
*
|
|
10
|
+
* It previously (and originally) defaulted to Infinity, which was later changed,
|
|
11
|
+
* because it's somewhat dangerous to run "infinite number of parallel promises".
|
|
12
|
+
* You can still emulate the old behavior by passing `Infinity`.
|
|
18
13
|
*/
|
|
19
14
|
concurrency?: number
|
|
20
15
|
|
|
@@ -36,6 +31,14 @@ export interface PMapOptions {
|
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
/**
|
|
34
|
+
* Forked from https://github.com/sindresorhus/p-map
|
|
35
|
+
*
|
|
36
|
+
* Improvements:
|
|
37
|
+
* - Exported as { pMap }, so IDE auto-completion works
|
|
38
|
+
* - Included Typescript typings (no need for @types/p-map)
|
|
39
|
+
* - Compatible with pProps (that had typings issues)
|
|
40
|
+
* - Preserves async stack traces (in selected cases)
|
|
41
|
+
*
|
|
39
42
|
* Returns a `Promise` that is fulfilled when all promises in `input` and ones returned from `mapper` are fulfilled,
|
|
40
43
|
* or rejects if any of the promises reject. The fulfilled value is an `Array` of the fulfilled values returned
|
|
41
44
|
* from `mapper` in `input` order.
|
|
@@ -66,73 +69,30 @@ export async function pMap<IN, OUT>(
|
|
|
66
69
|
mapper: AbortableAsyncMapper<IN, OUT>,
|
|
67
70
|
opt: PMapOptions = {},
|
|
68
71
|
): Promise<OUT[]> {
|
|
69
|
-
const { logger = console } = opt
|
|
70
|
-
const ret: (OUT | typeof SKIP)[] = []
|
|
71
|
-
// const iterator = iterable[Symbol.iterator]()
|
|
72
72
|
const items = [...iterable]
|
|
73
73
|
const itemsLength = items.length
|
|
74
74
|
if (itemsLength === 0) return [] // short circuit
|
|
75
75
|
|
|
76
|
-
const { concurrency =
|
|
77
|
-
|
|
78
|
-
const errors: Error[] = []
|
|
79
|
-
let isSettled = false
|
|
80
|
-
let resolvingCount = 0
|
|
81
|
-
let currentIndex = 0
|
|
76
|
+
const { concurrency = 16, errorMode = ErrorMode.THROW_IMMEDIATELY, logger = console } = opt
|
|
82
77
|
|
|
83
78
|
// Special cases that are able to preserve async stack traces
|
|
84
|
-
|
|
79
|
+
// Special case: serial execution
|
|
85
80
|
if (concurrency === 1) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
for (const item of items) {
|
|
89
|
-
try {
|
|
90
|
-
const r = await mapper(item, currentIndex++)
|
|
91
|
-
if (r === END) break
|
|
92
|
-
if (r !== SKIP) ret.push(r)
|
|
93
|
-
} catch (err) {
|
|
94
|
-
if (errorMode === ErrorMode.THROW_IMMEDIATELY) throw err
|
|
95
|
-
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
96
|
-
errors.push(err as Error)
|
|
97
|
-
} else {
|
|
98
|
-
// otherwise, suppress (but still log via logger)
|
|
99
|
-
logger?.error(err)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
if (errors.length) {
|
|
105
|
-
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return ret as OUT[]
|
|
109
|
-
} else if (!opt.concurrency || items.length <= opt.concurrency) {
|
|
110
|
-
// Special case for concurrency == infinity or iterable.length < concurrency
|
|
111
|
-
|
|
112
|
-
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
113
|
-
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(
|
|
114
|
-
r => r !== SKIP && r !== END,
|
|
115
|
-
) as OUT[]
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
;(await Promise.allSettled(items.map((item, i) => mapper(item, i)))).forEach(r => {
|
|
119
|
-
if (r.status === 'fulfilled') {
|
|
120
|
-
if (r.value !== SKIP && r.value !== END) ret.push(r.value)
|
|
121
|
-
} else if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
122
|
-
errors.push(r.reason)
|
|
123
|
-
} else {
|
|
124
|
-
// otherwise, suppress (but still log via logger)
|
|
125
|
-
logger?.error(r.reason)
|
|
126
|
-
}
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
if (errors.length) {
|
|
130
|
-
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
|
|
131
|
-
}
|
|
81
|
+
return await pMap1(items, mapper, errorMode, logger)
|
|
82
|
+
}
|
|
132
83
|
|
|
133
|
-
|
|
84
|
+
// Special case: concurrency === Infinity or items.length <= concurrency
|
|
85
|
+
if (concurrency === Infinity || items.length <= concurrency) {
|
|
86
|
+
return await pMapAll(items, mapper, errorMode, logger)
|
|
134
87
|
}
|
|
135
88
|
|
|
89
|
+
// General case: execution with throttled concurrency
|
|
90
|
+
const ret: (OUT | typeof SKIP)[] = []
|
|
91
|
+
const errors: Error[] = []
|
|
92
|
+
let isSettled = false
|
|
93
|
+
let resolvingCount = 0
|
|
94
|
+
let currentIndex = 0
|
|
95
|
+
|
|
136
96
|
return await new Promise<OUT[]>((resolve, reject) => {
|
|
137
97
|
const next = (): void => {
|
|
138
98
|
if (isSettled) {
|
|
@@ -198,3 +158,76 @@ export async function pMap<IN, OUT>(
|
|
|
198
158
|
}
|
|
199
159
|
})
|
|
200
160
|
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
pMap with serial (non-concurrent) execution.
|
|
164
|
+
*/
|
|
165
|
+
async function pMap1<IN, OUT>(
|
|
166
|
+
items: IN[],
|
|
167
|
+
mapper: AbortableAsyncMapper<IN, OUT>,
|
|
168
|
+
errorMode: ErrorMode,
|
|
169
|
+
logger: CommonLogger | null,
|
|
170
|
+
): Promise<OUT[]> {
|
|
171
|
+
let i = 0
|
|
172
|
+
const ret: OUT[] = []
|
|
173
|
+
const errors: Error[] = []
|
|
174
|
+
|
|
175
|
+
for (const item of items) {
|
|
176
|
+
try {
|
|
177
|
+
const r = await mapper(item, i++)
|
|
178
|
+
if (r === END) break
|
|
179
|
+
if (r !== SKIP) ret.push(r)
|
|
180
|
+
} catch (err) {
|
|
181
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) throw err
|
|
182
|
+
if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
183
|
+
errors.push(err as Error)
|
|
184
|
+
} else {
|
|
185
|
+
// otherwise, suppress (but still log via logger)
|
|
186
|
+
logger?.error(err)
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
if (errors.length) {
|
|
192
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return ret
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
pMap with fully concurrent execution, like Promise.all
|
|
200
|
+
*/
|
|
201
|
+
async function pMapAll<IN, OUT>(
|
|
202
|
+
items: IN[],
|
|
203
|
+
mapper: AbortableAsyncMapper<IN, OUT>,
|
|
204
|
+
errorMode: ErrorMode,
|
|
205
|
+
logger: CommonLogger | null,
|
|
206
|
+
): Promise<OUT[]> {
|
|
207
|
+
if (errorMode === ErrorMode.THROW_IMMEDIATELY) {
|
|
208
|
+
return (await Promise.all(items.map((item, i) => mapper(item, i)))).filter(
|
|
209
|
+
r => r !== SKIP && r !== END,
|
|
210
|
+
) as OUT[]
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const ret: OUT[] = []
|
|
214
|
+
const errors: Error[] = []
|
|
215
|
+
|
|
216
|
+
for (const r of await Promise.allSettled(items.map((item, i) => mapper(item, i)))) {
|
|
217
|
+
if (r.status === 'fulfilled') {
|
|
218
|
+
if (r.value === END) break
|
|
219
|
+
if (r.value !== SKIP) ret.push(r.value)
|
|
220
|
+
} else if (errorMode === ErrorMode.THROW_AGGREGATED) {
|
|
221
|
+
errors.push(r.reason)
|
|
222
|
+
} else {
|
|
223
|
+
// otherwise, suppress (but still log via logger)
|
|
224
|
+
logger?.error(r.reason)
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
if (errors.length) {
|
|
229
|
+
throw new AggregateError(errors, `pMap resulted in ${errors.length} error(s)`)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
return ret
|
|
233
|
+
}
|