Iterators and Generators- Things you need to know as a Javascript app developer

The JavaScript territory, as we know it, has always given innovators a lot of room to spread their wings. With the jQuery team continually setting new benchmarks via each Javascript release, the developers of the planet earth have found themselves to be a busy lot. Javascript 1.7. has been instrumental in paving way for a remarkably fresh development approach. Inundated by a rich collection of patterns, Javascript 1.7 is undeniably the finest Javascript version available till date.
While the JavaScript territory is massive, let me draw your focus on two very important and effective features that really give Javascript its adrenaline shot of relevancy – Iterators and Generators. I’ll highlight the most crucial aspects that you must know about these features for being able to take their advantage to the fullest. Hope the details covered here would encourage you to choose Javascript 1.7 without taking a second thought.

Taking a closer look at Iterators

An iterator, in its bare bones, is an object that depicts the way the items can be accessed from a specific collection in a one-by-one sequence, while monitoring the current position of items within the respective sequence. To put it simple, an iterator in Javascript is an object that offers a next() method which when used, returns the proceeding items available in the sequence. One of the most significant advantages of using Iterators is that the next() method can also be used for raising a StopIteration exception in case the sequence has got exhausted. After having created an iterator object, you can use the same implicitly via Javascript. You also have the freedom to use this iterator object explicitly by calling next() repeatedly.

A brief on Iterable Iterators

An iterable iterator is the one which includes an @@iterator() internal method. While a majority of iterators in ES6 are iterable by default, all the generators that have been created via the generator functions also portray this behavior. Here’s the code snippet that you can use for creating an iterable iterator:

obj1 = [1,2];
obj2 = [3,4];
outputArray = (for (i of obj1) for (j of obj2) i * j);
for (var result of outputArray) {
    console.log(result);
 }

And now, some interesting insights on Generators

Well, generators refer to a specific type of functions that can be used for pausing an execution and later resuming it as per requirement. To put in simple words, a generator can easily pause itself from execution, thereby enabling the other part of the program to function without any disturbance. The only thing about generators is that they resume on their own. You need to have a specific piece of code that would instruct the generator to resume on its own. Here’s the syntax that’s used for defining a simple generator in ES6:

function* series(val){
        //code here
}

Here’s the code snippet that’s used for pausing a generator:

function* series(val){
    var index = 0;
    while(index < val){
        yield ++index;
    }
}
var count = series(5);
console.log(count.next().value); // '1'
console.log(count.next().value); // '2'
console.log(count.next().value); // '3'
console.log(count.next().value); // '4'
console.log(count.next().value); // '5'
console.log(count.next().done);  // 'true' 

In the above code snippet, it is the yield keyword that's used by generator function for pausing itself. That means, whenever the function encounters the yield keyword, it automatically pauses itself.
If you happen to be a Javascript app developer, there are some key pointers that must be kept in mind while using iterators and generators in Javascript:

1. Pay attention to the process of defining custom iterators

In Javascript, there are objects which represent specific collections of items and should hence be iterated in a particular format. If you are iterating over a range object then the same should return numbers in the respective range in a one-by-one style. Also, while iterating over an object that represents database query results, ensure that the object returns all rows one by one. Last, but definitely not the least, an iterator created for an infinite mathematical sequence such as the Fibonacci sequence must be capable of returning results in a one by one format, refraining the creation of an infinite length data structure.

2. Be careful while using Iterator() with arrays

Mentioned below is the code that's involved with using an Iterator() with arrays:

var wordArray = ['first', 'second', 'third'];
var wordIt = Iterator(wordArray);
for (var word in wordIt)
  console.log(word); // print each [index, word]

3. Get an insightful understanding of how other programming languages go about their business of implement iterators

In Python, there's a single method called _next_() which returns the next element. Also, this particular method raises a StopIteration exception under situations where there are no elements left to proceed with.
In C#, the iterators have a method called MoveNext() which advances the iterator and returns false when a particular iteration has progressed beyond the last element. Also, there is a property 'Current' which returns a current element.
In the very popular Java programming language, iterators have two specific methods viz:
next()- this method returns the next element
hasNext()- this method returns false in case there are no more elements to use

4. Understand the functioning of for-of loop

The all-new ECMAScript 6 comes quipped with a new loop called the for-of loop. This loop works with iterables and you need to turn the result into an iterable prior to using the for-of loop. Here's the function that's used for creating an iterator:

var createArrayIterator = { };
createArrayIterator[Symbol.iterator] = function() {
  var x = 0;
  return { 
    next: function() {
      x++;
      if (x % 4 == 0) return { value: undefined, done: true };
      return { value: 'Iterator item ' + x, done: false };
    }
  }
};

Here's the code that depicts the use of for-of loop:

for (var x of createArrayIterator) {
  console.log(x);
}

5. Generators can be easily terminated using a return statement

As a Javascript app developer, you need to be very careful when it comes to terminating a generator. You must acquaint yourself with the fact that generators can be terminated using a specially created return statement which would raise a StopIteration exception. Below mentioned is an example of cube() variant that uses a limit argument that terminates once the specified limit has been exceeded:

function *cube(){
  var fn1 = 1;
  while (1){
    var current = fn1*fn1*fn1;
    fn1++;
    yield current;
  }
}
var sequence = cube();
console.log(sequence.next());     // 1
console.log(sequence.next());     // 8
console.log(sequence.next());     // 27
console.log(sequence.next());     // 64
console.log(sequence.next());     // 125
console.log(sequence.next());     // 216
console.log(sequence.next());     // 343

6. Understand the effects of closing a generator

You must be familiar with the fact that all generators contain a close() method that enables a generator to close itself on its own. Well, there are multiple effects of closing a generator. The most prominent ones have been mentioned below:
If the finally clause throws an exception other than the StopIteration function, the exception is being propagated to the respective caller of the close() method.
The finally clauses that are active within the generator function are being run
Generator gets terminated

7. Understand the usage of generators as lightweight threads

Most of might not be aware of this. Generators can be efficiently used as lightweight threads. In simple words, you can easily break up a long-running task into some smaller steps and pause the entire task via a yield as shown below:

function* taskThreads() {
        yield *thread_1(); // call thread 1
        yield *thread_2(); //  call thread 2
        ...
        ...
        yield *thread_n(); //  call thread n
    }

The aforementioned taskThreads() will thus be executed via a scheduling function defined as: scheduleTasks(taskThreads());
The complete scheduling function will be like the one mentioned below:

function scheduleTasks(task) {
        setTimeout(function () {
            if (!task.next().done) {
                scheduleTasks(task);
                console.log(gen.next().value); // print thread value
            }
        }, 1000);
    }
scheduleTasks(taskThreads());

8. Generators can return as well as yield values

By recursively calling a generator function via yield, it becomes feasible for the generator to yield values. The only thing that needs a special mention here is that these values actually don't reach the specific location where the particular yield has been used. In accordance to the example that's been mentioned within point no.7, here's the code that's associated with the process wherein the returned value is being passed on to yield:

 function* scheduleTasks() {
        yield* thread_1();
        yield* thread_2();
    }
    function* thread_1() {
        yield "Thread 1 and part 1";
        yield "Thread 1 and part 2";
        yield "Thread 1 and part 3";
    }
    function* thread_2() {
        yield "Thread 2 and part 1";
        yield "Thread 2 and part 2";
        yield "Thread 2 and part 3";
    }

9. The let keyword has a significant role to play

Considered as yet another brilliant feature of ECMAScript 6, the let keywords is quite similar to the var keyword. It is being used for declaring a variable and follows block scoping approach wherein the variable declared by the user is no longer available after the block. The code snippet involved with the same is shown below:

{
    var scope1 = 'app';
    let scope2 = 'developer';

    console.log(scope1, scope2); // "app" "developer"
}

console.log(scope1); // "app"
console.log(scope2); // ReferenceError

Wrapping It All Up
Now that we have gotten around to gaining a reasonable understanding of iterators and generators, it is time to make up your mind on installing the latest Javascript 7.1 version that includes both these features in the right measure. Get going. Now.