jhusain / asyncgenerator

Asynchronous Generators for ES7
391 stars 22 forks source link

forEach canceling source observable #5

Closed josh closed 9 years ago

josh commented 9 years ago

Hey @jhusain, I was trying to work through a couple more transpile cases and ran into some issues.

Heres a pretty basic synchronous number generator and a simple take() function.

function* nums() {
  for (var n = 0; ; n++) {
    yield n;
  }
}

function take(generator, count) {
  var i = 1,
    ary = [];

  for (var value of generator) {
    ary.push(value);

    if (i >= count) {
      return ary;
    }
    i++;
  }
}

var n = nums();
take(n, 3) // => [0, 1, 2]
take(n, 3) // => [3, 4, 5]

I'd assume that sprinkling magic asyncs, awaits and for on all over should perverse the same behavior.

async function* nums() {
  for (var n = 0; ; n++) {
    yield n;
  }
}

async function take(generator, count) {
  var i = 1,
    ary = [];

  for (var value on generator) {
    ary.push(value);

    if (i >= count) {
      return ary;
    }
    i++;
  }
}

var n = nums();
await take(n, 3) // => [0, 1, 2]
await take(n, 3) // => [3, 4, 5]

I tried to think through what the transpiled output would be and got stuck.

function take(generator, count) {
  var i = 1,
    ary = [];

  // for...on is supposed to become forEach
  // forEach will return a Promise when the observer is "done"
  return generator.forEach(function(value) {
    ary.push(value);

    if (i >= count) {
      // So it seems this.return will cancel our generator observer completely.
      // Thats bad since the next time we call `take` the observer is done won't
      // emit more values.
      //
      // Also, our `ary` gets set as `generator`'s return value rather than this
      // forEach.
      return this.return(ary);
    }
    i++;
  });
}

I'm assuming I'm just doing the transpile incorrectly or maybe theres just a bug in the current library code.

Thanks again!