fix iterator closing in AsyncIterator.prototype.map polyfill

This commit is contained in:
Denis Pushkarev
2026-02-18 14:10:26 +02:00
parent f84786b28a
commit 53bb0f38e1
4 changed files with 53 additions and 19 deletions
+1 -1
View File
@@ -51,7 +51,7 @@
- Fixed `%AsyncFromSyncIteratorPrototype%` to make it a little stricter
- Fixed counter in some cases of some `AsyncIterator` methods
- Fixed order of async iterators closing
- Fixed iterator closing in `AsyncIterator.prototype.flatMap` polyfill
- Fixed iterator closing in `AsyncIterator.prototype.{ map, flatMap }` polyfills
- Fixed iterator closing in `AsyncIterator.prototype.take` polyfill with `return: null`
- Fixed validation `return()` result as object in `AsyncIterator.prototype.take` polyfill
- Fixed a lack of error in `structuredClone` polyfill on attempt to transfer multiple objects, some of which are non-transferable
@@ -23,26 +23,28 @@ var AsyncIteratorProxy = createAsyncIteratorProxy(function (Promise) {
closeAsyncIteration(iterator, doneAndReject, error, doneAndReject);
};
Promise.resolve(anObject(call(state.next, iterator))).then(function (step) {
try {
if (anObject(step).done) {
state.done = true;
resolve(createIterResultObject(undefined, true));
} else {
var value = step.value;
try {
var result = mapper(value, state.counter++);
try {
Promise.resolve(anObject(call(state.next, iterator))).then(function (step) {
try {
if (anObject(step).done) {
state.done = true;
resolve(createIterResultObject(undefined, true));
} else {
var value = step.value;
try {
var result = mapper(value, state.counter++);
var handler = function (mapped) {
resolve(createIterResultObject(mapped, false));
};
var handler = function (mapped) {
resolve(createIterResultObject(mapped, false));
};
if (isObject(result)) Promise.resolve(result).then(handler, ifAbruptCloseAsyncIterator);
else handler(result);
} catch (error2) { ifAbruptCloseAsyncIterator(error2); }
}
} catch (error) { doneAndReject(error); }
}, doneAndReject);
if (isObject(result)) Promise.resolve(result).then(handler, ifAbruptCloseAsyncIterator);
else handler(result);
} catch (error2) { ifAbruptCloseAsyncIterator(error2); }
}
} catch (error) { doneAndReject(error); }
}, doneAndReject);
} catch (error) { doneAndReject(error); }
});
});
@@ -41,5 +41,21 @@ QUnit.test('AsyncIterator#map', assert => {
assert.avoid();
}, error => {
assert.same(error, 42, 'rejection on a callback error');
}).then(() => {
let calls = 0;
const iterator = createIterator([1, 2, 3], {
next() { calls++; throw 43; },
});
const mapped = map.call(iterator, it => it);
return mapped.next().then(() => {
assert.avoid();
}, error => {
assert.same(error, 43, 'rejection on next() sync error');
assert.same(calls, 1, 'next() called once');
return mapped.next();
}).then(result => {
assert.true(result.done, 'done after next() sync error');
assert.same(calls, 1, 'next() not called again after sync error');
});
});
});
@@ -41,5 +41,21 @@ QUnit.test('AsyncIterator#map', assert => {
assert.avoid();
}, error => {
assert.same(error, 42, 'rejection on a callback error');
}).then(() => {
let calls = 0;
const iterator = createIterator([1, 2, 3], {
next() { calls++; throw 43; },
});
const mapped = map.call(iterator, it => it);
return mapped.next().then(() => {
assert.avoid();
}, error => {
assert.same(error, 43, 'rejection on next() sync error');
assert.same(calls, 1, 'next() called once');
return mapped.next();
}).then(result => {
assert.true(result.done, 'done after next() sync error');
assert.same(calls, 1, 'next() not called again after sync error');
});
});
});