rabbitco rabbitco - 7 months ago 21
Javascript Question

Why does this generator skip a yield outside the try block?

Background

I am experimenting with how

Generator.prototype.throw()
works and made this example:

var myGen = function *() {

try{
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}

catch(err) {

console.log(err);
}

yield 7;
yield 8;
yield 9;

}

var myIterator = myGen();

console.log(myIterator.next());
console.log(myIterator.next());
console.log(myIterator.next());

myIterator.throw(new Error('Bullocks!'));

console.log(myIterator.next());
console.log(myIterator.next());
console.log(myIterator.next());


which at runtime results in the following:

{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
[Error: Bullocks!]
{ value: 8, done: false }
{ value: 9, done: false }
{ value: undefined, done: true }


Question

I can understand that
yield 4
and the remaining part of the
try
block is skipped after throwing an error.

But why does the generator skip
yield 7
?

Answer

It doesn't skip yield 7. When you call throw(), the control flow goes into the catch block, the error is logged, and then the execution continues until the next yield upon which a new iterator result object { value: 7, done: false } is returned.

It's just that in your code you don't console.log this one particular result object. Try:

console.log(myIterator.throw(new Error('Bullocks!')));

This is explained in step 11 and 13 of the spec:

  1. Resume the suspended evaluation of genContext using abruptCompletion as the result of the operation that suspended it. Let result be the completion record returned by the resumed computation.
  2. (…)
  3. Return Completion(result).