4

iterator is used quite often, e.g. in spread operator, for/of-loop, in deconstructing, etc. But they are hidden. I wonder whether there are use cases where you would actively use the knowledge of how to implement an iterator?

For example, iterating over an array using an iterator is over complicated, as you can see below, and I wouldn't know why someone would implement an iterator by himself:

function arrayIterable(arr = []) {
    let index = 0;
    const len = arr.length;

    const arrayIterator = {
       next: () => {
           let result;
           if (index === len) {
             return { value: arr[index], done: true };            
           }
           result = { value: arr[index], done: false }
           index++;
           return result;           
       }
    };
    return arrayIterator;
}
const myArr = ['a','b','c','d'];
let iter = arrayIterator(myArr);
let result = iter.next();
while (!result.done) {
  console.log(result.value);
  result = iter.next();
}
thadeuszlay
  • 2,787
  • 7
  • 32
  • 67
  • Are you asking about *implementing* the iterator manually (instead of using a generator function), asking about *calling* the iterator manually (instead of using `for of`/`yield*`), or both? – Bergi Apr 26 '20 at 20:30
  • "*For example, iterating over an array*" - well, that's a pretty bad example, because iterating over an array is a solved problem and does not require an iterator. – Bergi Apr 26 '20 at 20:32
  • @Bergi implementing the iterator manually. Context: I was reading about iterators and was thinking how I could use that knowledge in my daily work. Other than knowing how it works behind the curtain, I am looking for use cases where I would actually use it actively. – thadeuszlay Apr 26 '20 at 20:40
  • You were given answers, feel free to comment. – Wiktor Zychla Apr 26 '20 at 20:46
  • 1
    In that case, using generator functions will accomplish the task easier in 99% of cases. You only need to implement iterator objects yourself if you want to add extra features that are not part of the iteration protocol, such as lookahead, accessing the current value, caching stuff, making an asynchronous iterator without the implicit queuing, or really just any functionality that needs to access the state of a running iterator directly. – Bergi Apr 26 '20 at 20:51
  • @Bergi Using the iterator in conjunction with a generator is the best use case then, if you want to manually implement an iterator? – thadeuszlay Apr 26 '20 at 20:53
  • @thadeuszlay What do you mean by "*in conjunction with*"? You just write a generator function, which when called creates the iterator. No need to implement the `.next()` method at all. You don't *want to* manually implement an iterator in the manner you've shown in the question. – Bergi Apr 26 '20 at 20:55
  • @Bergi .... unless I want to add extra features that are not part of the iteration protocol, right? If I want to do that, then I'd manually write the iterator, right? – thadeuszlay Apr 26 '20 at 21:07
  • @thadeuszlay Yes, but then you'd *not* use a generator function. – Bergi Apr 26 '20 at 21:09

3 Answers3

2

It's handy if you want to operate on a dataset lazily. A stream, a file, a database, you move from one row/record to the other and advance the iterator. No need to keep the history in memory.

Since you don't have to maintain the whole source in memory, you can also handle the case of infinite data sources.

The biggest win of an iterator is at the client side. In a pre-iterator era code you are usually given an array-like object that exposes the indexing. However, in a modern code you could be given an iterator which means the client handles more general results with the same code. Consult the discussion under this question for an example case.

Wiktor Zychla
  • 47,367
  • 6
  • 74
  • 106
1

I don't think the knowledge of how it is implemented would be used to actually iterate over the thing. There is no advantage to that over using a for of loop.

But suppose you are building a JavaScript library, such as the Node.js driver for a MongoDB database. You want to make it easy to query the database and loop over the results. You implement the iterable protocol and then people can do this:

const cursor = queryDatabase(<some query>)
for (let doc of cursor) {
// do something with doc
}

In fact, the MongoDB Driver really does do this (except that they implement an async iterator).

EDIT: Note the benefit of using the iterator protocol over returning an array-like object from queryDatabase(). In MongoDB specifically, the cursor does not hold all of the results. It is a handle, and results of the query can be obtained by calling cursor.next()

The problem with having to call cursor.next() is that it is quite clunky, as you pointed out in the question. Yet it is good because not all of the results need to be fetched from the database, of which there could be thousands. So the iterator protocol is a way to keep the benefits of cursor.next() without having to deal with the ugly syntax.

  • Yeah, I was thinking the same. You only need that knowledge if you want to implement a library or a framework yourself. Other than that knowing how to implement an iterator has no _practical_ value. – thadeuszlay Apr 26 '20 at 20:32
  • 1
    That only partially answer the question. The database querying would be equally easy to use if the result would be given as an array-like object. – Wiktor Zychla Apr 26 '20 at 20:38
  • @WiktorZychla I agree. It should be noted that, in this specific example of a Node driver, there is a benefit to using an iterator over an array-ilke object. The downside to an array-like object is that it has to hold all of the results, yet the `cursor` works by fetching results from the DB one by one by caling `cursor.next()` So the iterator protocol is a good alternative for the clunky `cursor.next` syntax, without having the downside of the array-like object having to get all the results. – Bruno Ribarić Apr 26 '20 at 21:11
0

You can find a comprehensive introduction to iterator techniques in JavaScript on MDN:

See MDN: Iteration protocols

It also contains application areas, uses and examples.

Niklas E.
  • 1,848
  • 4
  • 13
  • 25