Skip to content

Commit e3fff42

Browse files
committed
Fix #21
1 parent c99090a commit e3fff42

File tree

2 files changed

+83
-1
lines changed

2 files changed

+83
-1
lines changed

src/asyncGeneratorMap.mjs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,17 @@ async function * asyncGeneratorMap (iterable, iteratee, queueOrConcurrency = 1,
183183
if (result.snapshot.status === 'rejected') {
184184
throw result.snapshot.reason
185185
} else {
186-
yield result.snapshot.value
186+
let yielded = false
187+
try {
188+
yield result.snapshot.value
189+
yielded = true
190+
} finally {
191+
if (!yielded)
192+
{
193+
await it.return()
194+
return
195+
}
196+
}
187197
}
188198
}
189199
if (exhausted && lastIndexFetched === lastIndexHandled) {

src/asyncGeneratorMap.test.mjs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -632,3 +632,75 @@ test('asyncGeneratorMap reaches concurrency', async () => {
632632
expect(maxConcurrency).toStrictEqual(expectedConcurrency)
633633
expect(result).toStrictEqual(await asyncIterableToArray(range(100)))
634634
})
635+
636+
test('common for await interrupts generator on interrupted iteration', async () => {
637+
638+
let finallyReached = false;
639+
640+
async function *asyncGenWithFinally() {
641+
try {
642+
for (const element of range(10)) {
643+
yield element;
644+
}
645+
} finally {
646+
finallyReached = true;
647+
}
648+
}
649+
650+
for await (const n of asyncGenWithFinally()) {
651+
if (n === 2) {
652+
break
653+
}
654+
}
655+
656+
expect(finallyReached).toBe(true);
657+
})
658+
659+
test('common for await calls AsyncGenerator.return() not AsyncGenerator.throw()', async () => {
660+
661+
let catchedException = null;
662+
663+
async function *asyncGenWithFinally() {
664+
try {
665+
for (const element of range(10)) {
666+
yield element;
667+
}
668+
} catch (e) {
669+
catchedException = e;
670+
}
671+
}
672+
673+
try {
674+
for await (const n of asyncGenWithFinally()) {
675+
if (n === 2) {
676+
throw new TestError();
677+
}
678+
}
679+
} catch (e) // ignore
680+
{
681+
expect(e instanceof TestError).toBe(true)
682+
}
683+
expect(catchedException).toBe(null);
684+
})
685+
686+
test('asyncGeneratorMap interrupts generator on interrupted iteration', async () => {
687+
688+
let finallyReached = false;
689+
690+
async function *asyncGenWithFinally() {
691+
try {
692+
for (const element of range(10)) {
693+
yield element;
694+
}
695+
} finally {
696+
finallyReached = true;
697+
}
698+
}
699+
700+
for await (const n of asyncGeneratorMap(asyncGenWithFinally(), n => n*2)) {
701+
if (n === 4) {
702+
break
703+
}
704+
}
705+
expect(finallyReached).toBe(true);
706+
})

0 commit comments

Comments
 (0)