Home > Software engineering >  Can generator function execution continue after an error is thrown in this pattern?
Can generator function execution continue after an error is thrown in this pattern?

Time:12-16

These docs make me think the answer could potentially be yes - but I always thought no and my tests show the same.

The reason for my question is that a generator function seems to have done exactly this in my project exactly once, and I cannot recreate it, nor can I find any error in my code - so I started thinking the error is in my assumptions.

function* someMethod(i) {
  try {
    yield i;
    throw new Error('error text');
    yield call(anotherMethod); // << This should never be executed, right?
  } catch (err) {
    console.error(err);
  }

CodePudding user response:

A generator function's execution will stop and the generator will be closed when an error is thrown, and the error will be propagated to the calling code. This is because when an error is thrown, it interrupts the normal flow of execution in the generator function and causes it to terminate early.

CodePudding user response:

Your "pattern" is incomplete, so we can't tell what else is going on. Yes, the line marked by the comment, right after the throw statement, will never be executed. But the line inside the catch block, and the lines after it, will execute - and they can contain more yield expressions, which will suspend the execution and allow it to be resumed later:

function* someMethod(i) {
  try {
    yield 'start it up';
    yield 'This is not executed'; // if the previous line throws
  } catch (err) {
    yield 'but this is';
  }
  yield 'and so is this';
}
const gen = someMethod();
console.log(gen.next());
console.log(gen.throw());
console.log(gen.next());
console.log(gen.next());

This can be used to create generators that will never end and can always be continued, no matter what you .throw() at them:

function* ignoreErrors() {
  while (true) {
    try {
      yield;
    } catch(e) {}
  }
}

We can even build generators on which you can invoke .return() and they won't stop:

function* forever() {
  try {
    yield;
  } finally {
    return yield* forever();
  }
}

or without relying on tail recursion (which is neither specified nor implemented for this anyway), but even more horrible code:

function* forever() {
  run: while (true) {
    try {
      yield;
    } finally {
      continue run;
    }
  }
}
  • Related