throwing/breaking inside a for-of loop does not call iterator.throw()

Marius Gundersen gundersen at gmail.com
Wed Aug 23 20:40:44 UTC 2017


This is something I stumbled across while looking into the for-of-with (aka
continue-with/break-with). It seems like throwing inside a for-of loop does
not call the iterators throw method, it calls the return method and it
seems to disregard the result of the method. For eample:

```js
var gen = () => ({
  x:0,
  [Symbol.iterator](){
    return this;
  },
  next(p){
    console.log('next', p, this.x);
    return {done: false, value: this.x++};
  },
  return(p){
    console.log('return', p);
    return {done: false, value: 'return'};
  },
  throw(p){
    console.log('throw', p);
    return {done: false, value: 'throw'};
  }
});

for(const g of gen()){ throw 'test' }
// next undefined 0
// return undefined
```

Shouldn't it call the throw method on the iterator, and then use the return
value to determine if it will actually return from the loop or not? This
would be useful for generators, which can catch the error and deal with it,
and continue to yield values even after throw and return have been called:

```
function* gen() {
  while(true) {
    try {
       yield 42;
    } catch(e) {
      console.log('Error caught!');
    }
  }
}

var g = gen();
g.next();
// { value: 42, done: false }
g.throw('Something went wrong');
// "Error caught!"
// { value: 42, done: false }
```

Unfortunately this example behaves differently if you try to loop over
gen() in a for-of loop
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170823/f4ff6362/attachment-0001.html>


More information about the es-discuss mailing list