javascript - 在 for-of 循​​环中等待与在 for-of 之前获取可迭代对象

标签 javascript node.js hyperledger-fabric

请参阅下面的两个代码块:

for await (const {key, value} of ctx.stub.getStateByRange(startKey, endKey)) {}

let allCarsRangeIterator = await ctx.stub.getStateByRange(startKey, endKey);
for (const {key, value} of allCarsRangeIterator ) {}

当我使用第一个时,一切正常,但当我使用第二个时,我收到一条错误,指出 allCarsRangeIterator 不可迭代。

为什么这两个不等价?

最佳答案

我发现这是一个非常有趣的问题,并进行了一些研究。让我们看看我能否正确回答这个问题:

首先我们需要明确iterators and generators ,所以我鼓励大家仔细阅读链接的文档。

以下似乎是一个生成器:

ctx.stub.getStateByRange(startKey, endKey)

根据文档,生成器是一种特殊类型的迭代器,只能迭代一次。最重要的是,它似乎是一个执行一些异步计算的生成器。让我们用一个更简单的函数来模拟它:

async function* foo() {
  yield 1;
  yield new Promise((resolve) => setTimeout(resolve, 2000, 2));
  yield 3;
}

根据文档,为了使对象可迭代,它需要实现 Symbol.asyncIterator (异步)或Symbol.iterator (同步)协议(protocol)。让我们检查一下:

async function* foo() {
  yield 1;
  yield new Promise((resolve) => setTimeout(resolve, 2000, 2));
  yield 3;
}

(async function () {
  const obj1 = foo();
  console.log(typeof obj1[Symbol.iterator] === "function"); // false
  console.log(typeof obj1[Symbol.asyncIterator] === "function"); // true
})();

现在让我们看看使用 await 时的输出.

async function* foo() {
  yield 1;
  yield new Promise((resolve) => setTimeout(resolve, 2000, 2));
  yield 3;
}

(async function () {
  const obj1 = await foo();
  console.log(typeof obj1[Symbol.iterator] === "function"); // false
  console.log(typeof obj1[Symbol.asyncIterator] === "function"); // true
})();

还是一样。这符合您得到的错误:allCarsRangeIterator is not iterable ,因为obj1没有实现Symbol.iterator协议(protocol)而是 Symbol.asyncIterator协议(protocol)。

所以,当您尝试使用for (const num of await foo())时,它是一个同步代码,所以它会寻找 Symbol.iterator协议(protocol)实现。但由于您的函数是一个异步生成器,因此它只有 Symbol.asyncIterator协议(protocol)已实现。

因此,迭代异步生成器的唯一方法是:

for await (const num of foo()) {
    console.log(num);
}

您还会发现这是有效的(尽管看起来很奇怪)

for await (const num of await foo()) {
    console.log(num);
}

(const num of await foo())仍然有Symbol.asyncIterator协议(protocol)已实现。


事实上,在 VSCode 中,每当您键入 for (const num of await foo()) 时,您都会看到一条警告:

Type 'AsyncGenerator<any, void, unknown>' must have a '[Symbol.iterator]()' method that returns an iterator. ts(2488)

const obj1 = await foo()显示警告:

'await' has no effect on the type of this expression. ts(80007)


其他资源:

  1. for...await of
  2. iterable and iterator protocols

关于javascript - 在 for-of 循​​环中等待与在 for-of 之前获取可迭代对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/73551865/

相关文章:

javascript - 向 Google map 添加自定义控件(添加流量层切换)

javascript - 在嵌套的 Angular 重复中维护计数器

hyperledger-fabric - 为组织添加用户时常见连接配置文件丢失错误

javascript - 解析云更新唯一列

javascript - 如何强制(Javascript)数据表请求按顺序触发?

javascript - Mongoose 中的链静态方法不起作用

hyperledger-fabric - 如何在 fabric v1.3.0 中启用私有(private)数据

hyperledger-fabric - 订购者组织的 Hyperledger Fabric 所有权

node.js - NodeJs : util. promisify 回调函数有多个参数

mysql - sails js 认证中间件