Iterators are objects that allow the traversal of iterables. They often have return values at their end.
Generators are functions that allow uncontinuous execution. They act as a special kind of iterator and only run when the next value is needed.
Regular iterators and generators do not allow the use of asynchronous operations, like file reading, inside their functions. To allow such operations, some languages have asynchronous iterators and generators.
Asynchronous Iterators are iterators that allow asynchronous operations inside. To demonstrate how an asynchronous iterator is written, the following example converts a regular iterator to an asynchronous one:
const iterable = [0, 1, 2, 3, 4] //Initializing an iterablelet i = 0iterator={[Symbol.iterator] () { //Initialize a Symbol.iterator objectreturn {next: ()=> { //next function repeats until the iterator finishesif (i < iterable.length){return {done: false, value: iterable[i++]} //Return the result as value}return {done: true} //Return {done: true} when iterator is done}}}};for (let result of iterator){ //For let loop runs iteratorconsole.log(result)}
As can be seen in the example, only minor changes are needed to convert a regular synchronous iterator into an asynchronous iterator. Both iterators are used here to traverse a list.
There is no async operation being used in the asynchronous iterator in the example above.
Asynchronous generators are also quite similar to synchronous generators, as the following example demonstrates:
const iterable = [0, 1, 2, 3, 4]function* generator(list){ //The * signifies that the function can return multiple valuesfor (x in list){yield x //yield is used to return the value}}for (let result of generator(iterable)){ //Function is called inside for let loopconsole.log(result)}
Again, this example only iterates over a list and prints its content. No asynchronous operation is being used in the asynchronous generator; however, it is completely possible to use.
Free Resources