Iterator、Generator

95 阅读2分钟

一、Iterator

Iterator(遍历器)为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署了该接口就可以使用 for of 遍历。

它的遍历过程是:

  1. 创建一个指针,指向当前数据结构的起始位置;
  2. 第一次调用指针的next()时,指针会指向数据结构的第一个成员,不断调用直到结束。

每次调用后,返回{value done}两个属性的对象,value当前值,done表示遍历是否结束。

Iterator接口部署在Symbol.iterator属性上,一个数据结构只要具有该属性,就认为是可遍历的

typeof obj[Symbol.iterator]  === 'function'

原生具备 Iterator 接口的数据结构:

  • 数组、字符串、伪数组对象
  • Map、Set
  • NodeList对象

二、Generator

在 js 中,一个函数一旦开始执行,就会运行到最后或遇到return结束,运行期间不会有其它代码能够打断它,也不能从外部再传入值到函数体内。而Generator函数(生成器)的出现使得打破函数的完整运行成为了可能

Generator 函数是协程在 ES6 的实现,最大特点就是可以交出函数的执行权,可以暂停执行和恢复执行。

1. 语法

Generator 函数的特征:(1)星号 *(2)内部使用 yield(用在普通函数报错)。

调用 Generator 函数,并不会执行该函数,而是返回一个迭代器对象Iterator代表Generator函数内部的指针。然后只要调用迭代器的 next 方法,指针就会移到下一个 yield 或 return,并执行返回一个含有 value、done 两个属性的对象, Generator 函数是分段执行的,yield 暂停执行,next 恢复执行。

function* fn() {  
  yield 'hello';
  yield 'world';
  return 'finished';
}
let g = fn();  // 普通调用
g.next();  // { value: 'hello', done: false }
g.next();  // { value: 'world', done: false }
g.next();  // { value: 'finished', done: true }
g.next();  // { value: undefined, done: true }

注意:Genarator 和 async/await 都可以用 try...catch

2. yield 和 return 区别

  • 每次遇到 yield 就暂停执行,下一次再继续从该位置向后执行;而 return 不具备记忆位置的功能。
  • 一个函数只能执行一次return

3. 协程

协程的运行流程为:

  • 第1步,协程A开始执行
  • 第2步,协程A执行到一半,进入暂停,执行权转移到协程B
  • 第3步,协程B交还执行权
  • 第4步,协程A恢复执行

yield 命令就将执行权交给其他协程,等待执行权返回。

4. 应用场景

  1. 协程操作
  2. 将异步回调变成了同步代码

虽然Generator函数能够实现异步编程,但实际上我们很少用它来实现异步,因为ES7引入的 async 函数对Generator函数的流程又做了一层封装,使得异步方案使用更加方便。