Skip to content

Commit 0dbc9c6

Browse files
committed
Complete subIterators
1 parent 7f646d7 commit 0dbc9c6

File tree

3 files changed

+24
-7
lines changed

3 files changed

+24
-7
lines changed

index.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// TODO: Get inspired by Matteos https://github.com/mcollina/hwp/blob/main/index.js, eg AbortController is nice?
33
// FIXME: Check this https://twitter.com/matteocollina/status/1392056117128306691
44
// FIXME: Read up on https://tc39.es/ecma262/#table-async-iterator-optional and add return() and throw(). return() is called by a "for await" when eg. a "break" or a "throw" happens within it
5+
// TODO: Check docs here https://tc39.es/ecma262/#sec-operations-on-iterator-objects
6+
// TODO: Look into https://tc39.es/ecma262/#sec-iteratorclose / https://tc39.es/ecma262/#sec-asynciteratorclose
7+
// TODO: See "iteratorKind" in https://tc39.es/ecma262/#sec-runtime-semantics-forin-div-ofbodyevaluation-lhs-stmt-iterator-lhskind-labelset – see how it loops and validates the returned values
8+
// TODO: THERE*S ACTUALLY A "throw" method MENTION IN https://tc39.es/ecma262/#sec-generator-function-definitions-runtime-semantics-evaluation: "NOTE: Exceptions from the inner iterator throw method are propagated. Normal completions from an inner throw method are processed similarly to an inner next."
59
// TODO: Have option to persist order? To not use Promise.race()?
610
// TODO: Make a proper merge for async iterables by accepting multiple input iterables, see: https://twitter.com/matteocollina/status/1392056092482576385
711

@@ -62,17 +66,26 @@ export function bufferedAsyncMap (input, callback, options) {
6266
const markAsEnded = async (throwAnyError) => {
6367
if (!isDone) {
6468
isDone = true;
69+
70+
// TODO: Errors from here, how to handle? allSettled() ensures they will be caught at least
71+
await Promise.allSettled(
72+
[
73+
// Ensure the main iterators are completed
74+
...(mainReturnedDone ? [] : [asyncIterator]),
75+
...subIterators,
76+
]
77+
.map(item => item.return && item.return())
78+
);
79+
6580
// TODO: Could we use an AbortController to improve this? See eg. https://github.com/mcollina/hwp/pull/10
6681
bufferedPromises.clear();
82+
subIterators.clear();
6783

68-
// FIXME: Need to do the same for subiterators
69-
if (asyncIterator.return) {
70-
await asyncIterator.return();
71-
}
7284
if (throwAnyError && hasError) {
7385
throw hasError;
7486
}
7587
}
88+
7689
return { done: true, value: undefined };
7790
};
7891

@@ -97,6 +110,7 @@ export function bufferedAsyncMap (input, callback, options) {
97110
err: err instanceof Error ? err : new Error('Unknown subiterator error'),
98111
}))
99112
.then(async result => {
113+
// FIXME: If "result" is not an object, throw a type error: https://tc39.es/ecma262/#sec-iteratornext
100114
if ('err' in result || result.done) {
101115
subIterators.delete(currentSubIterator);
102116
}
@@ -119,6 +133,7 @@ export function bufferedAsyncMap (input, callback, options) {
119133
err: err instanceof Error ? err : new Error('Unknown iterator error'),
120134
}))
121135
.then(async result => {
136+
// FIXME: If "result" is not an object, throw a type error: https://tc39.es/ecma262/#sec-iteratornext
122137
if ('err' in result || result.done) {
123138
mainReturnedDone = true;
124139
return {

test/throw.spec.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ chai.use(sinonChai);
1818

1919
chai.should();
2020

21-
describe('bufferedAsyncMap() AsyncInterface throw()', () => {
21+
describe.skip('bufferedAsyncMap() AsyncInterface throw()', () => {
2222
const count = 6;
2323

2424
/** @type {AsyncIterable<number>} */

test/values.spec.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ describe('bufferedAsyncMap() values', () => {
382382
result.should.have.length(3).and.have.members([0, 1, 2]);
383383
});
384384

385-
it.only('should handle rejected value from map callback', async () => {
385+
it('should handle rejected value from map callback', async () => {
386386
const bufferSize = 5;
387387
const rejectionError = new Error('Rejection');
388388

@@ -427,7 +427,7 @@ describe('bufferedAsyncMap() values', () => {
427427
});
428428
});
429429

430-
it.only('should handle rejected value from generator map callback', async () => {
430+
it('should handle rejected value from generator map callback', async () => {
431431
const bufferSize = 5;
432432
const rejectionError = new Error('Rejection');
433433

@@ -490,6 +490,8 @@ describe('bufferedAsyncMap() values', () => {
490490

491491
iterators.should.be.of.length(6);
492492

493+
// Ensure all iterators has been completed
494+
493495
const iteratorsNext = iterators.map(async iterator =>
494496
iterator[Symbol.asyncIterator]()
495497
.next()

0 commit comments

Comments
 (0)