Detailed explanation of Iterator-Generator

1 iterator iterable object

2 native iterator objects

3 Iterators for custom classes

4 Generator understanding and function

5 Custom Builder Scenarios

6 Analysis of asynchronous processing scheme

Iterator-Iterator in JavaScript (understand)

Code to specifically add an iterator to an array.

 const names = ["abc", "cba", "nba"]
    
    // 给数组names创建一个迭代器(迭代器: names的迭代器)
    let index = 0
    const namesIterator = {
      next: function() {
        // done: Boolean
        // value: 具体值/undefined
        if (index < names.length) {
          return { done: false, value: names[index++] }
        } else {
          return { done: true }
        }
      }
    }

    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())

    // 数组nums
    const nums = [100, 24, 55, 66, 86]
    
    let indexNum = 0
    const numsIterator = {
      next: function() {
        // done: Boolean
        // value: 具体值/undefined
        if (indexNum < nums.length) {
          return { done: false, value: nums[indexNum++] }
        } else {
          return { done: true }
        }
      }
    }

Iterators - create iterators for arrays (learn)

Iterators for arbitrary arrays.

 const names = ["abc", "cba", "nba"]
    const nums = [100, 24, 55, 66, 86]

    // 封装一个函数
    function createArrayIterator(arr) {
      let index = 0
      return {
        next: function() {
          if (index < arr.length) {
            return { done: false, value: arr[index++] }
          } else {
            return { done: true }
          }
        }
      }
    }

    const namesIterator = createArrayIterator(names)
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())
    console.log(namesIterator.next())

    const numsIterator = createArrayIterator(nums)
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())
    console.log(numsIterator.next())

Iterable objects - Create iterable objects (understand)

Iterable objects and iterators are two things. Iterators are methods in iterable objects. Such objects can be iterated through iterators, and the value can be obtained through iteration.

 // 将infos变成一个可迭代对象
    /*
      1.必须实现一个特定的函数: [Symbol.iterator]
      2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
    */
    const infos = {
      friends: ["kobe", "james", "curry"],
      [Symbol.iterator]: function() {
        let index = 0
        const infosIterator = {
          next: function() {
            // done: Boolean
            // value: 具体值/undefined
            if (index < infos.friends.length) {
              return { done: false, value: infos.friends[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return infosIterator
      }
    }

    // 给infos创建一个迭代器, 迭代infos中的friends
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())


    // 可迭代对象必然具备下面的特点
    // const iterator = infos[Symbol.iterator]()
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())

    // 可迭对象可以进行for of操作
    for (const item of infos) {
      console.log(item)
    }


    // 可迭代对象必然有一个[Symbol.iterator]函数
    // 数组是一个可迭代对象
    const students = ["张三", "李四", "王五"]
    console.log(students[Symbol.iterator])
    const studentIterator = students[Symbol.iterator]()
    console.log(studentIterator.next())
    console.log(studentIterator.next())
    console.log(studentIterator.next())
    console.log(studentIterator.next())

Iterable objects - Iterable object optimization (understanding)

1

   // 将infos变成一个可迭代对象
    /*
      1.必须实现一个特定的函数: [Symbol.iterator]
      2.这个函数需要返回一个迭代器(这个迭代器用于迭代当前的对象)
    */
   // 1.迭代infos中friends
    // const infos = {
    //   friends: ["kobe", "james", "curry"],
    //   [Symbol.iterator]: function() {
    //     let index = 0
    //     const infosIterator = {
    //       next: () => {
    //         if (index < this.friends.length) {
    //           return { done: false, value: this.friends[index++] }
    //         } else {
    //           return { done: true }
    //         }
    //       }
    //     }
    //     return infosIterator
    //   }
    // }

    // 2.迭代infos中的key/value
    const infos = {
      name: "why",
      age: 18,
      height: 1.88,

      [Symbol.iterator]: function() {
        // const keys = Object.keys(this)
        // const values = Object.values(this)
        const entries = Object.entries(this)
        let index = 0
        const iterator = {
          next: function() {
            if (index < entries.length) {
              return { done: false, value: entries[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    // 给infos创建一个迭代器, 迭代infos中的friends
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())
    // console.log(infosIterator.next())


    // 可迭代对象必然具备下面的特点
    // const iterator = infos[Symbol.iterator]()
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())
    // console.log(iterator.next())

    // 可迭对象可以进行for of操作
    for (const item of infos) {
      const [key, value] = item
      console.log(key, value)
    }

iterable object - native iterable object

The way to verify whether it is an iterable object is whether the [Symbol.iterator]() method can be called and the for of can be used to obtain the value.

 // 1.数组
    // const names = ["abc", "cba", "nba"]
    // for (const name of names) {
    //   console.log(name)
    // }
    // console.log(names[Symbol.iterator]())

    // 2.Set
    // const set = new Set(["abc", "cba", "nba"])
    // for (const item of set) {
    //   console.log(item)
    // }
    // const setIterator = set[Symbol.iterator]()
    // console.log(setIterator.next())
    // console.log(setIterator.next())
    // console.log(setIterator.next())
    // console.log(setIterator.next())

    // 3.arguments
    function foo() {
      for (const arg of arguments) {
        console.log(arg)
      }
    }

    foo(123, 321, 111, 222)

Iterable Objects - Iterable Object Scenarios

1

 // 1.用在特定的语法上
    const names = ["abc", "cba", "nba"]
    const info = {
      name: "why",
      age: 18,
      height: 1.88,
      [Symbol.iterator]: function() {
        const values = Object.values(this)
        let index = 0
        const iterator = {
          next: function() {
            if (index < values.length) {
              return { done: false, value: values[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    function foo(arg1, arg2, arg3) {
      console.log(arg1, arg2, arg3)
    }

    foo(...info)

    // 2.一些类的构造方法中, 也是传入的可迭代对象
    const set = new Set(["aaa", "bbb", "ccc"])
    const set2 = new Set("abc")
    console.log(set2)
    const set3 = new Set(info)
    console.log(set3)


    // 3.一些常用的方法
    const p1 = Promise.resolve("aaaa")
    const p2 = Promise.resolve("aaaa")
    const p3 = Promise.resolve("aaaa")
    const pSet = new Set()
    pSet.add(p1)
    pSet.add(p2)
    pSet.add(p3)
    Promise.all(pSet).then(res => {
      console.log("res:", res)
    })

    function bar() {
      // console.log(arguments)
      // 将arguments转成Array类型
      const arr = Array.from(arguments)
      console.log(arr)
    }

    bar(111, 222, 333)

Iterable objects - iteration of custom classes

Iterate over the class properties of the class.

 class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      running() {}
      [Symbol.iterator]() {
        let index = 0
        const iterator = {
          next: () => {
            if (index < this.friends.length) {
              return { done: false, value: this.friends[index++] }
            } else {
              return { done: true }
            }
          }
        }
        return iterator
      }
    }

    const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])
    const p2 = new Person("kobe", 30, 1.98, ["curry", "james", "aonier", "weide"])

    for (const item of p2) {
      console.log(item)
    }

Iterable Objects - Breaking of Iterators (Understanding)

break, return, and throw can all interrupt iterators

  class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      running() {}
      [Symbol.iterator]() {
        let index = 0
        const iterator = {
          next: () => {
            if (index < this.friends.length) {
              return { done: false, value: this.friends[index++] }
            } else {
              return { done: true }
            }
          },
          return: () => {
            console.log("监听到迭代器中断了")
            return { done: true }
          }
        }
        return iterator
      }
    }

    
    const p1 = new Person("why", 18, 1.88, ["curry", "kobe", "james", "tatumu"])

    for (const item of p1) {
      console.log(item)
      if (item === "kobe") {
        break
      }
    }

Generator - Generator function basic usage

 /*
      生成器函数: 
        1.function后面会跟上符号: *
        2.代码的执行可以被yield控制
        3.生成器函数默认在执行时, 返回一个生成器对象
          * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
          * 当遇到yield时, 就会中断执行
    */

    // 1.定义了一个生成器函数
    function* foo() {
      console.log("1111")
      console.log("2222")
      yield
      console.log("3333")
      console.log("4444")
      yield
      console.log("5555")
      console.log("6666")
    }

    // 2.调用生成器函数, 返回一个 生成器对象
    const generator = foo()
    // 调用next方法
    generator.next()
    generator.next()
    generator.next()

generator - generator function argument return value

The generator can return relevant parameters in conjunction with the return value of the iterator.

Regarding how to pass parameters to next, you need to use a writing method similar to this, where aaaa is the parameter returned by the next() call. And name2 is equivalent to the use of formal parameters.

When passing parameters for the first execution, write them directly in the formal parameters of the function.

// yield "aaaa"
const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
   // const names = ["abc", "cba", "nba"]
    // const iterator = names[Symbol.iterator]()
    // console.log(iterator.next())

    /*
      生成器函数: 
        1.function后面会跟上符号: *
        2.代码的执行可以被yield控制
        3.生成器函数默认在执行时, 返回一个生成器对象
          * 要想执行函数内部的代码, 需要生成器对象, 调用它的next操作
          * 当遇到yield时, 就会中断执行
    */

    // 1.定义了一个生成器函数
    function* foo(name1) {
      console.log("执行内部代码:1111", name1)
      console.log("执行内部代码:2222", name1)
      // yield "aaaa"
      const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
      // yield "bbbb"
      const name3 = yield "bbbb"
      // return "bbbb"
      console.log("执行内部代码:5555", name3)
      console.log("执行内部代码:6666", name3)
      yield "cccc"
      return undefined
    }

    // 2.调用生成器函数, 返回一个 生成器对象
    const generator = foo("next1")
    // 调用next方法
    // console.log(generator.next()) // { done: false, value: "aaaa" }
    // console.log(generator.next()) // { done: false, value: "bbbb" }
    // console.log(generator.next()) //  { done: false, value: "cccc" }
    // console.log(generator.next()) // {done: true, value: undefined}

    // 3.在中间位置直接return, 结果
    // console.log(generator.next()) // { done: false, value: "aaaa" }
    // console.log(generator.next()) // { done: true, value: "bbbb" }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }
    // console.log(generator.next()) // { done: true, value: undefined }

    // 4.给函数每次执行的时候, 传入参数
    console.log(generator.next())
    console.log(generator.next("next2"))
    console.log(generator.next("next3"))
    // console.log(generator.next())

generator - generator function ends early

You can directly end early through return, but what we need is a controllable early end. At this time, use return() directly instead of next()

 

 function* foo(name1) {
      console.log("执行内部代码:1111", name1)
      console.log("执行内部代码:2222", name1)
      const name2 = yield "aaaa"
      console.log("执行内部代码:3333", name2)
      console.log("执行内部代码:4444", name2)
      const name3 = yield "bbbb"
      // return "bbbb"
      console.log("执行内部代码:5555", name3)
      console.log("执行内部代码:6666", name3)
      yield "cccc"

      console.log("最后一次执行")
      return undefined
    }

    const generator = foo("next1")

    // 1.generator.return提前结束函数
    // console.log(generator.next())
    // console.log(generator.return("next2"))
    // console.log("-------------------")
    // console.log(generator.next("next3"))
    // console.log(generator.next("next4"))

    // 2.generator.throw向函数抛出一个异常
    console.log(generator.next())
    console.log(generator.throw(new Error("next2 throw error")))
    console.log("-------------------")
    console.log(generator.next("next3"))
    console.log(generator.next("next4"))

Generators - generators instead of iterators

Generators are special iterators, so you can use generators to iterate over iterative objects.

 // 1.对之前的代码进行重构(用生成器函数)
    const names = ["abc", "cba", "nba"]
    const nums = [100, 22, 66, 88, 55]

    function* createArrayIterator(arr) {
      for (let i = 0; i < arr.length; i++) {
        yield arr[i]
      }
      // yield arr[0]
      // yield arr[1]
      // yield arr[2]
      // return undefined
    }

    // const namesIterator = createArrayIterator(names)
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())

    // const numsIterator = createArrayIterator(nums)
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())
    // console.log(numsIterator.next())

    // 2.生成器函数, 可以生成某个范围的值
    // [3, 9)
    function* createRangeGenerator(start, end) {
      for (let i = start; i < end; i++) {
        yield i
      }
    }

    const rangeGen = createRangeGenerator(3, 9)
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())
    console.log(rangeGen.next())

Generator - generator yield syntactic sugar

yield* can directly iterate the following iterable object.

Writing generators in classes is different from usual

 // 1.yield*替换之前的方案
    // const names = ["abc", "cba", "nba"]
    // const nums = [100, 22, 66, 88, 55]

    // function* createArrayIterator(arr) {
    //   yield* arr
    // }

    // const namesIterator = createArrayIterator(names)
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())
    // console.log(namesIterator.next())

    // 2.yield替换类中的实现
    class Person {
      constructor(name, age, height, friends) {
        this.name = name
        this.age = age
        this.height = height
        this.friends = friends
      }

      // 实例方法
      *[Symbol.iterator]() {
        yield* this.friends
      }
    }

    const p = new Person("why", 18, 1.88, ["kobe", "james", "curry"])
    for (const item of p) {
      console.log(item)
    }

    const pIterator = p[Symbol.iterator]()
    console.log(pIterator.next())
    console.log(pIterator.next())
    console.log(pIterator.next())
    console.log(pIterator.next())

Asynchronous processing-asynchronous request code structure (important)

Generator functions can solve some callback hell. async and await are syntactic sugar for generators.

  // 封装请求的方法: url -> promise(result)
    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(url)
        }, 2000)
      })
    }

    // 1.发送一次网络请求
    // requestData("http://why").then(res => {
    //   console.log("res:", res)
    // })

    /*
      需求: 
        1.发送一次网络请求, 等到这次网络请求的结果
        2.发送第二次网络请求, 等待这次网络请求的结果
        3.发送第三次网络请求, 等待这次网络请求的结果
    */
    // 方式一: 层层嵌套(回调地狱 callback hell)
    // function getData() {
    //   // 1.第一次请求
    //   requestData("why").then(res1 => {
    //     console.log("第一次结果:", res1)

    //     // 2.第二次请求
    //     requestData(res1 + "kobe").then(res2 => {
    //       console.log("第二次结果:", res2)

    //       // 3.第三次请求
    //       requestData(res2 + "james").then(res3 => {
    //         console.log("第三次结果:", res3)
    //       })
    //     })
    //   })
    // }

    // 方式二: 使用Promise进行重构(解决回调地狱)
    // 链式调用
    // function getData() {
    //   requestData("why").then(res1 => {
    //     console.log("第一次结果:", res1)
    //     return requestData(res1 + "kobe")
    //   }).then(res2 => {
    //     console.log("第二次结果:", res2)
    //     return requestData(res2 + "james")
    //   }).then(res3 => {
    //     console.log("第三次结果:", res3)
    //   })
    // }

    // 方式三: 最终代码
    // function* getData() {
    //   const res1 = yield requestData("why")
    //   console.log("res1:", res1)

    //   const res2 = yield requestData(res1 + "kobe")
    //   console.log("res2:", res2)

    //   const res3 = yield requestData(res2 + "james")
    //   console.log("res3:", res3)
    // }

    // const generator = getData()
    // generator.next().value.then(res1 => {
    //   generator.next(res1).value.then(res2 => {
    //     generator.next(res2).value.then(res3 => {
    //       generator.next(res3)
    //     })
    //   })
    // })

    // 方式四: async/await的解决方案
    async function getData() {
      const res1 = await requestData("why")
      console.log("res1:", res1)

      const res2 = await requestData(res1 + "kobe")
      console.log("res2:", res2)

      const res3 = await requestData(res2 + "james")
      console.log("res3:", res3)
    }

    const generator = getData()

Asynchronous processing - optimization of generator code (understanding)

Because there are many layers, we want to automatically call

 // 封装请求的方法: url -> promise(result)
    function requestData(url) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve(url)
        }, 2000)
      })
    }

    // 生成器的处理方案
    function* getData() {
      const res1 = yield requestData("why")
      console.log("res1:", res1)

      const res2 = yield requestData(res1 + "kobe")
      console.log("res2:", res2)

      const res3 = yield requestData(res2 + "james")
      console.log("res3:", res3)

      const res4 = yield requestData(res3 + "curry")
      console.log("res4:", res4)

      const res5 = yield requestData(res4 + "tatumu")
      console.log("res5:", res5)
    }

    // const generator = getData()
    // generator.next().value.then(res1 => {
    //   generator.next(res1).value.then(res2 => {
    //     generator.next(res2).value.then(res3 => {
    //       generator.next(res3).value.then(res4 => {
    //         generator.next(res4)
    //       })
    //     })
    //   })
    // })

    // 自动化执行生成器函数(了解)
    function execGenFn(genFn) {
      // 1.获取对应函数的generator
      const generator = genFn()
      // 2.定义一个递归函数
      function exec(res) {
        // result -> { done: true/false, value: 值/undefined }
        const result = generator.next(res)
        if (result.done) return
        result.value.then(res => {
          exec(res)
        })
      }
      // 3.执行递归函数
      exec()
    }

    execGenFn(getData)

Guess you like

Origin blog.csdn.net/weixin_56663198/article/details/131722983