You-Dont-Know-JS
You-Dont-Know-JS copied to clipboard
ES6 & Beyond: Early Completion
Hi! In the Early Completion section there is a sentence:
In addition to return(..) being callable manually, it's also called automatically at the end of iteration by any of the ES6 constructs that consume iterators, such as the for..of loop and the ... spread operator.
So to check it out I created a custom iterable object with the next() and return() methods in it. I put console.log inside the every method and was expected that at the end of the for..of statement, the return method of my object was called automatically. But it wasn't called! You can check out what I mean by this jsfiddle.
So if I understand it correctly, the automatic call happens only when there is break inside the for..of or we manually call return(). Maybe I got the phrase at the end of iteration incorrectly for some reason. Does it really mean like "the very last step of for..of"? Thanks!
Need to clarify this in the second edition, thanks.
The correct statement is that all iterators are closed automatically (what that sentence intended to say), but return()
itself is only called in an Abnormal completion, such as a break
or exception.
And by "all iterators are closed automatically" you mean they set their "state" to { value: undefined, done: true }, which is described in the previous sentence: Once a generator is completed, either normally or early as shown, it no longer processes any code or returns any values. Right?
Yes, and also if the iterator is attached to a generator, it will allow a pending finally
in that generator to always run (for cleanup sake), regardless of normal or early termination.
Hi,
Regarding early completion of an iterator, in ES6 & Beyond : Chap 3, you say
"By general convention, an iterator should not produce any more results after having called return(..) or throw(..)".
However, you can still produce values from an array iterator after a return
var arr = [1,2,3,4,5];
var it = arr[Symbol.iterator]();
for (var i of it)
{
console.log(i);
break;
}
console.log(it.next());
console.log(it.next());
And it prints 1, 2, and 3.
I've also noticed (with a custom iterator) that when you use incomplete destructuring, it calls return function. So when you make a second destructuring on the same iterator, like in your exemple below, it works for an array iterator, but not for an iterator that does not produce values after return.
var a = [1,2,3,4,5];
var it = a[Symbol.iterator]();
var [x,y] = it; // take just the first two elements from it <=== call return on the iterator
var [z, ...w] = it; // take the third, then the rest all at once <=== get undefined for a custom iterator implementing return
// is
it fully exhausted? Yep.
it.next(); // { value: undefined, done: true }
x; // 1
y; // 2
z; // 3
w; // [4,5]
Could you confirm ? Sorry if i misunderstund something.
Regards