This article will not be a dogmatic retelling of grammar, if you need grammar details please refer to Teacher Ruan Yifeng’s tutorial.

Why combine Iterator and Generator? Since the Generator is an implementation of the Iterator interface, the Generator follows the specification of the Iterator interface, and it would be confusing to look at the Generator syntax alone, so this is a tidy up.

What is an Iterator interface

Iterator is translated as an Iterator. An interface represents a specification for the output of a class of functions. Iterator would look something like this:

interface IteratorNextRet {
    done: boolean, value? :any
}

interface Iterator {
    next: ():IteratorNextRet,
    throw? : (a) :void.return? : (a) :void
}

function iterator() :Iterator {
    return {
        next() { return { done: true}}}}Copy the code

That is, the Iterator specifies that the output of the function must be an object with a next function, and that the next function outputs an object with done and value. The following throw and return are optional

The Iterator for of

Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator: Iterator

Var arr = [0, 1, 2, 3, 4, 5] arr[symbol.iterator] =function() {// this points to an instance const len = this.lengthlet idx = -1
    return {
        next: () => {
            idx += 2
            return {
                value: this[idx],
                done: idx >= len
            }
        }
    }
}
for (let i of arr) {
    console.log(i)
}
Copy the code

For of does something like this: generate a new iterator, execute next, and print value each time until next returns done as true, then stop printing value and iterating.

Iterator also has several applications (ps: You can try the following ones based on the above implementation) :

  1. [a1, a2] = ‘hello; ‘// a1: h, a2: e String. Prototype [Symbol. Iterator
  2. Var o = {} arr = […o
  3. Yield * is followed by a traversable structure, which invokes the traverser interface of that structure.

Generator

Generator is an implementation of the Iterator interface. We have overridden the Iterator in the same way as a normal function.

var arr = [0.1.2.3.4.5]
arr[Symbol.iterator] = function* () {
    const len = this.length
    for (let i = 0; i <= len; i++) {
        if (i%2= = =1 && i > 0) {
            yieldi; }}}for (let i of arr) console.log(i) / / 1, 3, 5
// Even you can
for (let j of arr[Symbol.iterator]()) console.log(j) / / 1 3 5
Copy the code

The code is much cleaner than before and the logic is much simpler. You can see from the comparison of the two codes what the * does with the yield syntax. * indicates that this function is a Generator. And when a sister spawn an instance once it gives you active new, yield is equivalent to the value returned by calling next, a Generator derived subclass.

function* gen() {
    var arr = [0.1.2]
    for (let v of arr) yield v
}
var g1 = gen()
var g2 = gen()
g1 === g2 // false
g1.next() // {value: 0, done: false}
g1.next() // {value: 1, done: false}
g1.next() // {value: 2, done: false}
g1.next() // {value: undefined, done: true}
Copy the code

The equivalent of the Generator is a pointer, where to point is determined by yield and when to point by the exposed next. Of course, there are two other API returns and throws. Each execution of the return and throw is equivalent to breaking the pointer, calling directly to the end (return), or falling into a catch statement (throw), and done is true.

yield*

Yield * is more like syntactic sugar in nature.

function* foo() {
    yield 1;
    yield 2;
}
function* bar() {
    yield 'a'; Foo () yield* foo(); yield'b';
}
for(var v of bar()) {console.log(v) // a 1 2 b} // equivalentfunction* bar() {
    yield 'a'
    for (var v of foo()) {
        yield v;
    }
    yield 'b'
}
Copy the code

How to implement a runner with class async await?

We say async await is the syntactic sugar of Generator. We try to simulate async functions with Generator so that we can see the difference in detail.

Assume a promise function following await.

// Simulate a FETCH interface
function fetch(time) {
  return function() {
    return new Promise((resolve, reject) = > {
      setTimeout(resolve, time)
    })
  }
}
// Initiators call generator next until done is true
function run(g) {
  const { value: ret, done } = g.next()
  if (done) {
    return Promise.resolve();
  } else {
    return ret.then((a)= > {
      return run(g)
    })
  }
}

var fetch1 = fetch(1000)
var fetch2 = fetch(2000)
function* gen() {
  console.log('Fetch1');
  yield fetch1();
  console.log('Fetch2')
  yield fetch2();
  console.log('done')}var g = gen();
console.log(run(g));
// Promise
// Start fetch1
/ / 1 s after
// Start executing fetch2
/ / 2 s after
// done
Copy the code

Assuming that sometimes “await” is not necessarily followed by a promise, it could very well be a Thunk function. The Thunk function might look like this :$.get(‘ XXX ‘).done(callback).

// Simulate data to get thunk function
function fetch(time) {
    return function() {
        let cb
        const ret = {
            done(callback) {
                cb = callback
            },
            exec() {
                cb && cb()
            }
        }
        setTimeout(ret.exec, time)
        return ret
    }
}
// Override an executor
function run(g) {
  const { value: ret, done } = g.next()
  if(! done) { ret.done(function() { run(g); }}})var fetch1 = fetch(1000)
var fetch2 = fetch(2000)
function* gen() {
  console.log('Fetch1');
  yield fetch1();
  console.log('Fetch2')
  yield fetch2();
  console.log('done')}var g = gen();
run(g);
// Start fetch1
// 1s 
// Start executing fetch2
// 2s
// done
Copy the code

You can see that a simplified version of the CO module is written. Of course, the assumptions here are more extreme, not so compatible. So if an interviewer asks you what is the difference between async and Generator?

Async is more semantic than Generator. Async functions automatically perform await below whereas Generator calls next manually. Async automatically returns a Promise function while Generator returns an Iterator interface.

The above.