TypeScript icon indicating copy to clipboard operation
TypeScript copied to clipboard

Fix asyncDelegator reporting "done" too early

Open apendua opened this issue 3 years ago • 0 comments

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.

apendua avatar Oct 22 '22 19:10 apendua