Fix asyncDelegator reporting "done" too early
Fixes #45400
I wasn't entirely sure where I should be adding unit tests for a fix like this one so would really appreciate some guidance in that area.
Regarding the fix itself, let me try to explain why I believe the previous code was incorrect. In the following snippet:
var __asyncDelegator =
(this && this.__asyncDelegator) ||
function (o) {
var i, p;
return (
(i = {}),
verb('next'),
verb('throw', function (e) {
throw e;
}),
verb('return'),
(i[Symbol.iterator] = function () {
return this;
}),
i
);
function verb(n, f) {
i[n] = o[n]
? function (v) {
return (p = !p)
? { value: __await(o[n](v)), done: n === "return" }
: f
? f(v)
: v;
}
: f;
}
};
the iterator returned by __asyncDelegator reports done = true one step too early when iterator.return() is called. Instead it should emit { value: __await(o[n](v)), done: false } and wait until the correlated __asyncGenerator will call iterator.next(...) with the result of the promise wrapped with __await, say result = { value, done }, obtained from the inner generator via o.return(v). Since iterator is alternating it's behavior on each call (because of p = !p), iterator.next will return { value, done } explicitly this time and if result.done happens to be true, then the processing will stop as expected. On the other hand, if result.done = false, e.g. when there is a yield in finally block, the processing will continue until done = true is eventually observed.