LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 311|回复: 0

异步可迭代对象

[复制链接]
发表于 2024-1-21 23:45:39 | 显示全部楼层 |阅读模式
当值是以异步的形式出现时,例如在 setTimeout 或者另一种延迟之后,就需要异步迭代。

最常见的场景是,对象需要发送一个网络请求以传递下一个值,稍后我们将看到一个它的真实示例。

要使对象异步迭代:

使用 Symbol.asyncIterator 取代 Symbol.iterator。
next() 方法应该返回一个 promise(带有下一个值,并且状态为 fulfilled)。
关键字 async 可以实现这一点,我们可以简单地使用 async next()。
我们应该使用 for await (let item of iterable) 循环来迭代这样的对象。
注意关键字 await。
作为开始的示例,让我们创建一个可迭代的 range 对象,与前面的那个类似,不过现在它将异步地每秒返回一个值。

我们需要做的就是对上面代码中的部分代码进行替换:

let range = {
  from: 1,
  to: 5,

  [Symbol.asyncIterator]() { // (1)
    return {
      current: this.from,
      last: this.to,

      async next() { // (2)

        // 注意:我们可以在 async next 内部使用 "await"
        await new Promise(resolve => setTimeout(resolve, 1000)); // (3)

        if (this.current <= this.last) {
          return { done: false, value: this.current++ };
        } else {
          return { done: true };
        }
      }
    };
  }
};

(async () => {

  for await (let value of range) { // (4)
    alert(value); // 1,2,3,4,5
  }

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

为了使一个对象可以异步迭代,它必须具有方法 Symbol.asyncIterator (1)。
这个方法必须返回一个带有 next() 方法的对象,next() 方法会返回一个 promise (2)。
这个 next() 方法可以不是 async 的,它可以是一个返回值是一个 promise 的常规的方法,但是使用 async 关键字可以允许我们在方法内部使用 await,所以会更加方便。这里我们只是用于延迟 1 秒的操作 (3)。
我们使用 for await(let value of range) (4) 来进行迭代,也就是在 for 后面添加 await。它会调用一次 range[Symbol.asyncIterator]() 方法一次,然后调用它的 next() 方法获取值。
这是一个对比 Iterator 和异步 iterator 之间差异的表格:

Iterator                                异步                  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,而不是 Symbol.asyncIterator。

for..of 的情况和这个一样:没有 await 关键字时,则期望找到的是 Symbol.iterator。

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表