The source of the whole complexity of the iterator-next-method technique for defining an iterable is the demand to decouple the code of the iterable from the code that uses all the values produced by the iterable. Without this demand, the entire code of the NumberIterable example would collapse into trivial code:
for(let i=0; i<=x; i++) alert(i);
The complication of using a next method is necessary to carry out this code decoupling. The next method call is the way in which producer and consumer of values synchronize, the producer remains in a waiting state until the consumer requires a new value by calling the next method, then it resumes running in order to produce the new value, and then it goes back to ...