Skip to content

💤

多个迭代器

从语法使用方面来看就,通过一个迭代器控制生成器的时候,似乎是在控制声明的生成器函数。但是有一个细微之处很容易忽略:每次构建一个迭代器,实际上就隐式构建了一个生成器的一个实例,通过这个迭代器来控制的是这个生成器实例。

同一个生成器的多个实例可以同时运行,它们甚至可以彼此交互:

javascript
var z = 1
function* foo() {
  var x = yield 2
  z++
  var y = yield x * z
  console.log(x, y, z)
}

var it1 = foo()
var it2 = foo()

var val1 = it1.next().value // 2
var val2 = it2.next().value // 2

val1 = it1.next(val2 * 10).value // 40
val2 = it2.next(val1 * 5).value // 600

it1.next(val2 / 2) //
it2.next(val1 / 4) //
  1. *foo()的两个实例同时启动,两个next()分别从yield 2语句得到值 2。

  2. it1.next(val2 * 10),也就是it1.next(20),发送到第一个生成器实例it120会替换上一个yield及后面的表达式 —— var x = 20,同时从下一个yield语句得到值x * z —— 20 * 2,将val1设置为 40。

  3. it2.next(val1 * 5),也就是it2.next(200),发送到第二个生成器实例it2200会替换上一个yield及后面的表达式 —— var x = 200,同时从下一个yield语句得到值x * z —— 200 * 3,将val2设置为 600。

  4. it1.next(val2 / 2),也就是it1.next(600 / 3),发送到第一个生成器实例it1200会替换上一个yield及后面的表达式 —— var y = 300,然后打印出 x y z 的值分别是 20 300 3。

  5. it2.next(val1 / 4),也就是it2.next(40 / 4),发送到第二个生成器实例it210会替换上一个yield及后面的表达式 —— var y = 10,然后打印出 x y z 的值分别是 200 10 3。

generator -> async/await

javascript
function delay(time, val) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(val)
    }, time)
  })
}

function* foo() {
  const r2P = yield delay(1000, 'res2')
  const r3P = yield delay(500, 'res3')

  return [r2P, r3P]
}

function* bar() {
  const r1 = yield delay(1000, 'res1')

  const res = yield* foo()
  console.log('res:', r1, res) // res: res1 [ 'res2', 'res3' ]
}

const it = bar()

const p0 = it.next().value

p0.then(res => {
  const p1 = it.next(res).value
  p1.then(res => {
    const p2 = it.next(res).value
    p2.then(res => {
      it.next(res)
    })
  })
})

25 行及以后的代码,可以封装为一个工具方法,用于自动处理 resolve/reject 以及错误处理。但是我不会。