📕
blog
  • Hi there
  • javascript
    • 柯里化 - Curry
    • 观察者和订阅-发布模式
    • generator
    • 发布订阅-依赖于window
    • pwa manual trigger install
  • browser
    • beautify scrollbar
  • http
    • nginx 缓存配置
  • extra
    • vue-cli 不使用 .env[.xxx] 文件,添加额外运行时参数
    • docker-compose nginx with ssl config
  • React
    • How React works
Powered by GitBook
On this page
  • 让一个对象支持for...of遍历
  • Async Iterator
  • Async generator
  • Async Iterator
  • 总结

Was this helpful?

  1. javascript

generator

让一个对象支持for...of遍历

  • 方法一

const range = {
  from: 0,
  to: 10,

  [Symbol.iterator]() {
    return { // 第一次会使用current的值
      current: this.from,
      last: this.to,

      next() { // 后续每次for...of都会调用next(),当done为true时候结束调用
        if (this.current <= this.last) {
          return {
            done: false,
            value: this.current++
          }
        }
        return {
          done: true
        }
      }
    }
  }
}


console.log([...range]) // (11) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
  • 方法二

const rangeUsingGenerator = {
  from: 0,
  to: 10,

  *[Symbol.iterator]() { // generator函数返回就是一个iterable,所以不需要写current ,next 那些
    for (let value = this.from; value <= this.to; value++) yield value
  }
}


console.log([...rangeUsingGenerator]) // output is same as before

Async Iterator

为了使对象可以异步迭代:

  1. 我们需要使用 Symbol.asyncIterator 取代 Symbol.iterator。

  2. next() 方法应该返回一个 promise。

  3. 我们应该使用 for await (let item of iterable) 循环来迭代这样的对象

const asyncGenerator = {
  from: 0,
  to: 10,

  [Symbol.asyncIterator]() { // (1)
    return {
      current: this.from,
      last: this.to,
      async next() { // (2)
        if (this.current <= this.last) {
          await new Promise((resolve) => setTimeout(resolve, 1000)) // (3)
          return {
            done: false,
            value: this.current++
          }
        }
        return {
          done: true
        }
      }
    }
  }
}

const run = async () => {
  for await (let value of asyncGenerator) { // (4)
    console.log(value)
  }
}

run()

正如我们所看到的,其结构与常规的 iterator 类似:

  1. 为了使一个对象可以异步迭代,它必须具有方法 Symbol.asyncIterator (1)。

  2. 这个方法必须返回一个带有 next() 方法的对象,next() 方法会返回一个 promise (2)。

  3. 这个 next() 方法可以不是 async 的,它可以是一个返回值是一个 promise 的常规的方法,但是使用 async 关键字可以允许我们在方法内部使用 await,所以会更加方便。这里我们只是用于延迟 1 秒的操作 (3)。

  4. 我们使用 for await(let value of range) (4) 来进行迭代,也就是在 for 后面添加 await。它会调用一次 range[Symbol.asyncIterator]() 方法一次,然后调用它的 next() 方法获取值。

Iterator

Async Iterator

提供 iterator 的对象方法

Symbol.iterator

Symbol.asyncIterator

next() 返回的值是

任意值

Promise

要进行循环,使用

for..of

for await..of

Spread 语法 ... 无法异步工作

需要常规的同步 iterator 的功能,无法与异步 iterator 一起使用。

例如,spread 语法无法工作:

alert( [...range] ); // Error, no Symbol.iterator

这很正常,因为它期望找到 Symbol.iterator,跟 for..of 没有 await 一样。并非 Symbol.asyncIterator。

Async generator

async function* asyncGenerator(from = 0, to) {
  for (let i = from; i <= to; i++) {
    await new Promise((resolve) => setTimeout(resolve, 1000))
    yield i
  }
}

const run = async () => {
  for await (let value of asyncGenerator(0, 10)) {
    console.log(value)
  }
}

run()

Async Iterator

const asyncIteratorObj = {
  from: 0,
  to: 10,

  async *[Symbol.asyncIterator]() {
    for (let value = this.from; value <= this.to; value++) {
      await new Promise((resolve) => setTimeout(resolve, 500))
      yield value
    }
  }
}

const run = async () => {
  for await (let value of asyncIteratorObj) {
    console.log(value)
  }
}

run()

总结

常规的 iterator 和 generator 可以很好地处理那些不需要花费时间来生成的的数据。

当我们期望异步地,有延迟地获取数据时,可以使用它们的 async counterpart,并且使用 for await..of 替代 for..of。

Async iterator 与常规 iterator 在语法上的区别:

Iterable

Async Iterable

提供 iterator 的对象方法

Symbol.iterator

Symbol.asyncIterator

next() 返回的值是

{value:…, done: true/false}

resolve 成 {value:…, done: true/false} 的 Promise

Async generator 与常规 generator 在语法上的区别:

Generator

Async generator

声明方式

function*

async function*

next() 返回的值是

{value:…, done: true/false}

resolve 成 {value:…, done: true/false} 的 Promise

在 Web 开发中,我们经常会遇到数据流,它们分段流动(flows chunk-by-chunk)。例如,下载或上传大文件。

我们可以使用 async generator 来处理此类数据。值得注意的是,在一些环境,例如浏览器环境下,还有另一个被称为 Streams 的 API,它提供了特殊的接口来处理此类数据流,转换数据并将数据从一个数据流传递到另一个数据流(例如,从一个地方下载并立即发送到其他地方)。

Previous观察者和订阅-发布模式Next发布订阅-依赖于window

Last updated 4 years ago

Was this helpful?