Skip to content

Commit 3c1d416

Browse files
committed
fixup! support iterable objects: String Map Set
1 parent 2e98b99 commit 3c1d416

12 files changed

+709
-942
lines changed

lib/array.js

+71-110
Original file line numberDiff line numberDiff line change
@@ -5,31 +5,29 @@ const { asyncIter } = require('./async-iterator.js');
55
const { promisify } = require('util');
66

77
// Asynchronous map (iterate parallel)
8-
// items - <Array>, incoming
8+
// items - <Iterable>, incoming
99
// fn - <Function>, to be executed for each value in the array
1010
// current - <any>, current element being processed in the array
1111
// callback - <Function>
1212
// err - <Error> | <null>
1313
// value - <any>
1414
// done - <Function>, on done, optional
1515
// err - <Error> | <null>
16-
// result - <Array>
17-
const map = (items, fn, done) => {
18-
done = done || common.emptyness;
16+
// result - <Iterable>
17+
const map = (items, fn, done = common.emptyness) => {
1918
if (!items[Symbol.iterator]) {
20-
done(new TypeError('items is not iterable'));
19+
done(new TypeError('"items" argument is not iterable'));
2120
return;
2221
}
2322
const isArray = Array.isArray(items);
24-
const data = asyncIter(items).map(item => promisify(fn)(item));
25-
const promise = isArray ? data.toArray() : data.collectTo(items.constructor);
26-
promise.then(res => done(null, res), done);
23+
asyncIter(items)
24+
.parallel(item => promisify(fn)(item))
25+
.then(res => done(null, isArray ? res : new items.constructor(res)))
26+
.catch(done);
2727
};
2828

29-
const DEFAULT_OPTIONS = { min: 5, percent: 0.7 };
30-
3129
// Non-blocking synchronous map
32-
// items - <Array>, incoming dataset
30+
// items - <Iterable>, incoming dataset
3331
// fn - <Function>
3432
// item - <any>
3533
// index - <number>
@@ -38,90 +36,53 @@ const DEFAULT_OPTIONS = { min: 5, percent: 0.7 };
3836
// percent - <number>, ratio of map time to all time
3937
// done - <Function>, call on done
4038
// err - <Error> | <null>
41-
// result - <Array>
42-
const asyncMap = (items, fn, options = {}, done) => {
39+
// result - <Iterable>
40+
const asyncMap = (items, fn, options = {}, done = common.emptyness) => {
4341
if (typeof options === 'function') {
4442
done = options;
45-
options = DEFAULT_OPTIONS;
43+
options = {};
4644
}
47-
48-
const len = items.length || items.size;
49-
const name = items.constructor.name;
50-
let result = done ? new items.constructor() : null;
51-
const data = common.iter(items);
52-
53-
if (!len || result === null) {
54-
if (done) done(null, result);
45+
if (!items[Symbol.iterator]) {
46+
done(new TypeError('"items" argument is not iterable'));
5547
return;
5648
}
57-
58-
const min = options.min || DEFAULT_OPTIONS.min;
59-
const percent = options.percent || DEFAULT_OPTIONS.percent;
60-
61-
let begin;
62-
let sum = 0;
63-
let count = 0;
64-
65-
const ratio = percent / (1 - percent);
66-
67-
const countNumber = () => {
68-
const loopTime = Date.now() - begin;
69-
const itemTime = sum / count;
70-
const necessaryNumber = (ratio * loopTime) / itemTime;
71-
return Math.max(necessaryNumber, min);
72-
};
73-
74-
const next = () => {
75-
const itemsNumber = count ? countNumber() : min;
76-
const iterMax = Math.min(len, itemsNumber + count);
77-
78-
begin = Date.now();
79-
for (; count < iterMax; count++) {
80-
const itemResult = fn(data.next().value, count);
81-
if (done) {
82-
if (name === 'String') result += itemResult;
83-
else if (name === 'Array') result.push(itemResult);
84-
else if (name === 'Set') result.add(itemResult);
85-
else result.set(itemResult);
86-
}
87-
}
88-
sum += Date.now() - begin;
89-
90-
if (count < len) {
91-
begin = Date.now();
92-
setTimeout(next, 0);
93-
} else if (done) {
94-
done(null, result);
95-
}
96-
};
97-
98-
next();
49+
const isArray = Array.isArray(items);
50+
const iter = asyncIter(items)
51+
.map(item => promisify(fn)(item))
52+
.throttle(options.percent, options.min);
53+
const collect = isArray ? iter.toArray() : iter.collectTo(items.constructor);
54+
collect.then(res => done(null, res)).catch(done);
9955
};
10056

10157
// Asynchronous filter (iterate parallel)
102-
// items - <Array>, incoming
58+
// items - <Iterable>, incoming
10359
// fn - <Function>, to be executed for each value in the array
10460
// value - <any>, item from items array
10561
// callback - <Function>
10662
// err - <Error> | <null>
10763
// accepted - <boolean>
10864
// done - <Function>, on done, optional
10965
// err - <Error> | <null>
110-
// result - <Array>
111-
const filter = (items, fn, done) => {
112-
done = done || common.emptyness;
66+
// result - <Iterable>
67+
const filter = (items, fn, done = common.emptyness) => {
11368
if (!items[Symbol.iterator]) {
114-
done(new TypeError('items is not iterable'));
69+
done(new TypeError('"items" argument is not iterable'));
11570
return;
11671
}
11772
const isArray = Array.isArray(items);
118-
const data = asyncIter(items).filter(item => promisify(fn)(item));
119-
const promise = isArray ? data.toArray() : data.collectTo(items.constructor);
120-
promise.then(res => done(null, res), err => done(err));
73+
asyncIter(items)
74+
.parallel(async item => [await promisify(fn)(item), item])
75+
.then(res => {
76+
const filtered = res
77+
.filter(([predicateResult]) => predicateResult)
78+
.map(([, item]) => item);
79+
done(null, isArray ? filtered : new items.constructor(filtered));
80+
})
81+
.catch(done);
12182
};
12283

12384
// Asynchronous reduce
124-
// items - <Array>, incoming
85+
// items - <Iterable>, incoming
12586
// fn - <Function>, to be executed for each value in array
12687
// previous - <any>, value previously returned in the last iteration
12788
// current - <any>, current element being processed in the array
@@ -131,21 +92,21 @@ const filter = (items, fn, done) => {
13192
// data - <any>, resulting value
13293
// counter - <number>, index of the current element
13394
// being processed in array
134-
// items - <Array>, the array reduce was called upon
95+
// items - <Iterable>, the array reduce was called upon
13596
// done - <Function>, on done, optional
13697
// err - <Error> | <null>
137-
// result - <Array>
98+
// result - <Iterable>
13899
// initial - <any>, optional value to be used as first
139100
// argument in first iteration
140-
const reduce = (items, fn, done, initial) => {
141-
done = done || common.emptyness;
101+
const reduce = (items, fn, done = common.emptyness, initial) => {
142102
asyncIter(items)
143103
.reduce((prev, cur) => promisify(fn)(prev, cur), initial)
144-
.then(r => done(null, r), done);
104+
.then(res => done(null, res))
105+
.catch(done);
145106
};
146107

147108
// Asynchronous reduceRight
148-
// items - <Array>, incoming
109+
// items - <Iterable>, incoming
149110
// fn - <Function>, to be executed for each value in array
150111
// previous - <any>, value previously returned in the last iteration
151112
// current - <any>, current element being processed in the array
@@ -155,53 +116,53 @@ const reduce = (items, fn, done, initial) => {
155116
// data - <any>, resulting value
156117
// counter - <number>, index of the current element
157118
// being processed in array
158-
// items - <Array>, the array reduce was called upon
119+
// items - <Iterable>, the array reduce was called upon
159120
// done - <Function>, on done, optional
160121
// err - <Error> | <null>
161-
// result - <Array>
122+
// result - <Iterable>
162123
// initial - <any>, optional value to be used as first
163124
// argument in first iteration
164-
const reduceRight = (items, fn, done, initial) => {
165-
done = done || common.emptyness;
125+
const reduceRight = (items, fn, done = common.emptyness, initial) => {
166126
asyncIter(items)
167127
.reduceRight((prev, cur) => promisify(fn)(prev, cur), initial)
168-
.then(r => done(null, r), done);
128+
.then(res => done(null, res))
129+
.catch(done);
169130
};
170131

171132
// Asynchronous each (iterate in parallel)
172-
// items - <Array>, incoming
133+
// items - <Iterable>, incoming
173134
// fn - <Function>
174135
// value - <any>, item from items array
175136
// callback - <Function>
176137
// err - <Error> | <null>
177138
// done - <Function>, on done, optional
178139
// err - <Error> | <null>
179-
// items - <Array>
180-
const each = (items, fn, done) => {
181-
done = done || common.emptyness;
140+
// items - <Iterable>
141+
const each = (items, fn, done = common.emptyness) => {
182142
asyncIter(items)
183143
.parallel(item => promisify(fn)(item))
184-
.then(r => done(null, r), done);
144+
.then(res => done(null, res))
145+
.catch(done);
185146
};
186147

187148
// Asynchronous series
188-
// items - <Array>, incoming
149+
// items - <Iterable>, incoming
189150
// fn - <Function>
190151
// value - <any>, item from items array
191152
// callback - <Function>
192153
// err - <Error> | <null>
193154
// done - <Function>, on done, optional
194155
// err - <Error> | <null>
195-
// items - <Array>
196-
const series = (items, fn, done) => {
197-
done = done || common.emptyness;
156+
// items - <Iterable>
157+
const series = (items, fn, done = common.emptyness) => {
198158
asyncIter(items)
199159
.each(item => promisify(fn)(item))
200-
.then(r => done(null, r), done);
160+
.then(res => done(null, res))
161+
.catch(done);
201162
};
202163

203164
// Asynchronous find (iterate in series)
204-
// items - <Array>, incoming
165+
// items - <Iterable>, incoming
205166
// fn - <Function>,
206167
// value - <any>, item from items array
207168
// callback - <Function>
@@ -210,16 +171,15 @@ const series = (items, fn, done) => {
210171
// done - <Function>, on done, optional
211172
// err - <Error> | <null>
212173
// result - <any>
213-
const find = (items, fn, done) => {
214-
done = done || common.emptyness;
174+
const find = (items, fn, done = common.emptyness) => {
215175
asyncIter(items)
216176
.find(item => promisify(fn)(item))
217-
.then(r => done(null, r))
218-
.catch(e => done(e));
177+
.then(res => done(null, res))
178+
.catch(done);
219179
};
220180

221181
// Asynchronous every
222-
// items - <Array>, incoming
182+
// items - <Iterable>, incoming
223183
// fn - <Function>,
224184
// value - <any>, item from items array
225185
// callback - <Function>
@@ -228,16 +188,18 @@ const find = (items, fn, done) => {
228188
// done - <Function>, on done, optional
229189
// err - <Error> | <null>
230190
// result - <boolean>
231-
const every = (items, fn, done) => {
232-
done = done || common.emptyness;
191+
const every = (items, fn, done = common.emptyness) => {
233192
asyncIter(items)
234-
.every(item => promisify(fn)(item))
235-
.then(r => done(null, r))
236-
.catch(e => done(e));
193+
.parallel(item => promisify(fn)(item))
194+
.then(res => {
195+
const accepted = res.every(predicateResult => predicateResult);
196+
done(null, accepted);
197+
})
198+
.catch(done);
237199
};
238200

239201
// Asynchronous some (iterate in series)
240-
// items - <Array>, incoming
202+
// items - <Iterable>, incoming
241203
// fn - <Function>
242204
// value - <any>, item from items array
243205
// callback - <Function>
@@ -246,12 +208,11 @@ const every = (items, fn, done) => {
246208
// done - <Function>, on done
247209
// err - <Error> | <null>
248210
// result - <boolean>
249-
const some = (items, fn, done) => {
250-
done = done || common.emptyness;
211+
const some = (items, fn, done = common.emptyness) => {
251212
asyncIter(items)
252213
.some(item => promisify(fn)(item))
253-
.then(r => done(null, r))
254-
.catch(e => done(e));
214+
.then(res => done(null, res))
215+
.catch(done);
255216
};
256217

257218
module.exports = {

lib/async-iterator.js

+8-8
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,8 @@ class AsyncIterator {
192192
return this;
193193
}
194194

195-
throttle(percent) {
196-
return new ThrottleIterator(this, percent);
195+
throttle(percent, min) {
196+
return new ThrottleIterator(this, percent, min);
197197
}
198198

199199
enumerate() {
@@ -421,29 +421,29 @@ class ThrottleIterator extends AsyncIterator {
421421
this.ratio = percent / (1 - percent);
422422

423423
this.sum = 0;
424-
this.count = 0;
424+
this.iterCount = 0;
425425
this.begin = Date.now();
426426
this.iterMax = this.min;
427427
}
428428

429429
async next() {
430-
if (this.iterMax > this.count) {
431-
this.count++;
430+
if (this.iterMax > this.iterCount) {
431+
this.iterCount++;
432432
return await this.base.next();
433433
}
434434

435435
this.sum += Date.now() - this.begin;
436-
const itemTime = this.sum / this.count;
436+
const itemTime = this.sum / this.iterCount;
437437

438438
this.begin = Date.now();
439439
await timeout();
440440
const loopTime = Date.now() - this.begin;
441441

442442
const number = Math.max((this.ratio * loopTime) / itemTime, this.min);
443443

444-
this.iterMax = Math.round(number) + this.count;
444+
this.iterMax = Math.round(number) + this.iterCount;
445445

446-
this.count++;
446+
this.iterCount++;
447447
this.begin = Date.now();
448448
return await this.base.next();
449449
}

0 commit comments

Comments
 (0)