javascriptiteratorfor-of-loop

for...of an iterator without closing it


Is it possible to loop over part of an iterator with for...of without closing the iterator when I break the loop?

Example:

function* numbers(i=0){
  while(true) yield i++;
}

let nums=numbers();

// this loop prints numbers from 0 to 3
for(const n of nums){
  if(n>3) break;
  console.log(n);
}

// this loop doesn't print anything because `nums` has already been closed
for(const n of nums){
  if(n>10) break;
  console.log(n);
}

I know that I can go through the iterator on my own calling iterator.next(). But I wonder if it's possible to do this with the for...of syntax.


Solution

  • No. However you can provide a wrapper that doesn't forward return() to the generator:

    function unclosed(iterable) {
      return {
        [Symbol.iterator]() {
          const iterator = iterable[Symbol.iterator]();
          return {
            next: iterator.next.bind(iterator),
            return: null,
            throw: null,
          };
        },
      };
    }
    
    function* numbers(i=0) {
      try {
        while (true) yield i++;
      } finally {
        console.log('done');
      }
    }
    
    const nums = numbers();
    
    // this loop prints numbers from 0 to 3
    for (const n of unclosed(nums)) {
      console.log(n);
      if (n == 3) break;
    }
    // and this one the numbers from 4 to 10, as well as 'done'
    for (const n of nums) {
      console.log(n);
      if (n == 10) break;
    }