项目作者: tzachi81

项目描述 :
generators and Iterators in JS
高级语言: JavaScript
项目地址: git://github.com/tzachi81/generators.git
创建时间: 2019-08-19T09:51:45Z
项目社区:https://github.com/tzachi81/generators

开源协议:

下载


Generators and Iterators in JavaScript

Main points covered in this document

  • iterable data types and objects and the iterator protocol
  • generator functions and generator object
  • generator functions with promises and their late ES8 edtion: async/await.

1. What are iterators?


“iterator is an object which defines a sequence and potentially a return value upon its termination.” (MDN web docs)

Iterable data types and objects

  • for..in loop is for enumerable properties (including Object data type) - they return their object keys.
  • for..of loop is a method, introduced in ES2015, for iterating over “iterable collections” - they return their object values.
  • These are the objects/data-types that have a [Symbol.iterator] function built-in: Array, TypedArray, String, Map, Set.
  • for..of loop won’t work with Objects because they are not “iterable”, hence, don’t have the [Symbol.iterator] property by default.

Iterator protocol

An object is an iterator when it implements a next() method:

  • next() - returns an object with at least two properties:
    • done(bool) - indicates if passed all iterables
    • value(any) - returns the current iterable value, undefined for the value of {done: true}.
      ```js
      {value: “someValue”, done: false} // Example for iterator’s return object while in sequence.
      {value: undefined, done: true} // Example for iterator’s return object when the sequence is done no more values to yield).

Reference:

2. Generator object and generator functions


  • Generator functions are iterator protocol functions that can break the ‘Run-to-completion’ paradigm.
  • Calling a generator function does not execute its body immediately, but retuns a Generator object instead.
    To execute its body, you have to call the .next() method by its object reference, like so:
    1. //gen(), A.K.A the generator function, will return a generator object rather than executing the function's body:
    2. let iterator = gen();
    3. // calling the .next() method will start the generator function's body execution until it will hit the next yield expression.
    4. iterator.next();
  • Generator functions can get and pass values with a two-way communication using yield and next().
    “The yield keyword is used to pause and resume a generator function *()”. (from: MDN web docs)
  • The yield* expression is used to delegate to another generator or iterable object.
  • A return statement in the function generator will make it finish (done: true).
  • A throw exception in the function generator will make it finish (done: true).

Question: Is a generator object an iterator or an iterable?

Answer: An generator object is both iterator and iterable

References:

3. Async/Await vs. Generators with Promises

“Without generators, async functions are very difficult to handle.”

ES6 introduced us generators and promises, and ES8 introduced us a more elegant way to use it with async/await.

Why do we need to understand promises and generators?

  • Supporting older platforms.
  • Running on older browser versions or older Node.js versions.
  • Debugging potentially backwards compatibility compilers (like ‘babel’) issues with async functions.

browsers also implement async functions in a similar way:

  • they transform the async code to use generators and promises, quite similar to Babel.
    The early use of async/await in ES6 was done by using Generator functions that yielded promises.

The ES6 way to use async functions was by combining genrator functions with promises:

  1. const gen = function* generator() {
  2. const a = yield Promise.resolve(1);
  3. const b = yield Promise.resolve(2);
  4. return a + b;
  5. };
  6. const iterator = gen();
  7. console.log(iterator.next()); // { value: Promise(1), done: false }
  8. console.log(iterator.next()) // { value: Promise(2), done: false }
  9. console.log(iterator.next()) // { value: NaN, done: true }

In ES8 it can be translated to a more elegant code with async/await

  1. const promisory = async function test() {
  2. const a = await Promise.resolve(1);
  3. const b = await Promise.resolve(2);
  4. return a + b;
  5. };

References:

4. Further reading:

You-Dont-Know-JS, Async and Performance, Chapter4: Generators