ES6 引入了 for await ... of 新语法,用来遍历异步迭代器,很多人还不熟悉。本文是对它的简单解释

Node.js的继任者Deno发布了,主页上有一个如何使用它的小演示:

import { serve } from "https://deno.land/std@0.69.0/http/server.ts";
const s = serve({ port: 8000 });
console.log("http://localhost:8000/");
for await (const req of s) {
  req.respond({ body: "Hello World\n" });
}

当看到 for await (const req of s) 这种句式的时候不免感觉很惊讶。我们之前从来没有见过这种写法。

想象一下,当我阅读更多关于Deno的内容时,我发现这段代码实际上是有效的javascript脚本,它在Node.js中也是有效的,而我对此一无所知,这是多么令人惊讶
那么这是什么?为什么我从来没见过呢?我应该在哪里使用它?我是不是已经错过了?
如果你们有同样的问题,那很好!
这篇文章将尝试回答所有这些问题!

Iterators 迭代器

你见过这样的东西吗?

class RandomNumberGenerator {
  [Symbol.iterator]() {
    return {
      next: () => {
        return { value: Math.random() };
      },
    };
  }
}

如果你这样做了,那么对你来说很好,你可以跳到下一节!
如果您还没有,那么让我们深入了解一下它是怎么做的:

此类 RandomNumberGenerator 实现 [Symbol.iterator] 或 @@iterator 方法(当方法通过符号属性定义时,我们引用具有双 @@ 的方法)。
[Symbol.iterator] 或 @@iterator 方法在对象上定义时允许迭代对象!
由于现在我们将 @@iterator 方法定义为RandomNumberGenerator类的实例方法,因此该类的所有实例现在都是可迭代的。现在,您可以通过运行以下代码来测试它:

class RandomNumberGenerator {
  [Symbol.iterator]() {
    return {
      next: () => {
        return { value: Math.random() };
      },
    };
  }
}

const rand = new RandomNumberGenerator();

for (const random of rand) {
  console.log(random);
  if (random < 0.1) break;
}

为了使一切正常工作, @@iterator 方法必须返回一个包含 next 方法的对象,并且该 next 方法需要返回另一个具有 value 和 done 属性的对象。
value 将包含返回的值,而 done 将是一个布尔值,如果设置为TRUE,则结束迭代。
虽然 value 是强制的,但可以省略 done ,如上例所示(这允许我们定义无限个迭代量)。
我们现在可以让事情变得可迭代了!
这在什么时候会变得有用呢?
我相信这在很大程度上取决于您正在创建的业务逻辑的类型。

例如,我强烈推荐的Node.js Design Patterns一书给出了一个迭代Matrix元素的示例(您可能已经将其定义为数组的数组)。

但是,如果您需要我诚实的个人意见,我还没有遇到过这样的情况:“这是迭代器的一个很好的用例”。

无论如何,让我们回到我们文章的主题:我们还需要在for循环中添加等待吗?

异步迭代器

顾名思义,异步迭代器是我们在上面的例子的异步版本。
想象一下,我们不是返回随机数字,而是返回状态。那会是什么样子?
如果我们更改上面的示例来执行此操作,它将如下所示:

const simulateDelay = (val, delay) =>
  new Promise((resolve) => setTimeout(() => resolve(val), delay));

class RandomNumberGenerator {
  [Symbol.asyncIterator]() {
    return {
      next: async () => {
        return simulateDelay({ value: Math.random() }, 200); //return the value after 200ms of delay
      },
    };
  }
}

const rand = new RandomNumberGenerator();

(async () => {
  for await (const random of rand) {
    console.log(random);
    if (random < 0.1) break;
  }
})();

有哪些变化?

  1. 我们首先将符号属性更改为 asyncIterator ,而不仅仅是 iterator
  2. 我们使 next 方法成为一个异步函数。
  3. 我创建了simateDelay函数,该函数返回在给定时间后解析给定值的承诺。
  4. 我们在for循环中添加了await
  5. 我们将循环放在一个即时调用的函数表达式中,以避免顶级等待调用出现问题。(注意:在Node.js版本14+中不再需要此功能)

因此,我们制作了一个简单的程序,它能够迭代以异步方式获取其元素的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在 JavaScript 中,使用 `for..of` 或 `forEach` 循环来遍历一个数组或一个类数组对象时,是同步地进行的。如果在循环体内部调用了异步操作(例如调用接口),则会出现问题,因为循环不会等待异步操作完成,就直接执行下一次循环,导致结果不正确。 解决这个问题的方法是使用 `for await..of` 循环,它可以用于遍历支持异步迭代的对象,例如异步生成器和异步迭代器。使用 `for await..of` 循环可以确保在每次循环中等待异步操作完成后再执行下一次循环。 以下是使用 `for await..of` 循环调用接口的示例代码: ```javascript async function fetchData() { const urls = ['api/url1', 'api/url2', 'api/url3']; for await (const data of getData(urls)) { console.log(data); } } async function* getData(urls) { for (const url of urls) { const response = await fetch(url); const data = await response.json(); yield data; } } ``` 在上面的代码中,`fetchData` 函数调用了 `getData` 函数,并使用 `for await..of` 循环遍历异步生成器返回的数据。`getData` 函数接收一个 URL 数组,并使用 `for..of` 循环遍历 URL,调用 `fetch` 方法获取数据,然后使用 `yield` 关键字返回数据给异步生成器。在 `fetchData` 函数中,`for await..of` 循环等待异步生成器返回数据,并输出到控制台。这样就可以确保在每次循环中等待异步操作完成后再执行下一次循环,避免了使用 `forEach` 循环时出现的问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CHQIUU

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值