JavaScript教程:深入理解异步迭代器与生成器

JavaScript教程:深入理解异步迭代器与生成器

ru.javascript.info Современный учебник JavaScript ru.javascript.info 项目地址: https://gitcode.com/gh_mirrors/ru/ru.javascript.info

前言

在现代JavaScript开发中,处理异步数据流变得越来越常见。本文将带你深入理解JavaScript中的异步迭代器和生成器,这是处理异步数据流的强大工具。

同步迭代器回顾

在探讨异步迭代器之前,让我们先回顾一下常规的同步迭代器。一个可迭代对象需要实现Symbol.iterator方法,该方法返回一个迭代器对象,迭代器对象包含next()方法。

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

  [Symbol.iterator]() {
    return {
      current: this.from,
      last: this.to,

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

这种同步迭代器适用于数据立即可用的情况,但当我们需要处理异步获取的数据时,就需要异步迭代器了。

异步迭代器基础

异步迭代器与常规迭代器类似,但有三个关键区别:

  1. 使用Symbol.asyncIterator而非Symbol.iterator
  2. next()方法返回一个Promise
  3. 使用for await...of循环进行迭代

下面是一个异步迭代器的示例,它每秒产生一个值:

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

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

      async next() {
        await new Promise(resolve => setTimeout(resolve, 1000));
        
        if (this.current <= this.last) {
          return { done: false, value: this.current++ };
        } else {
          return { done: true };
        }
      }
    };
  }
};

(async () => {
  for await (let value of range) {
    console.log(value); // 1, 2, 3, 4, 5 (每秒一个)
  }
})();

异步生成器

异步生成器是创建异步迭代器的更简洁方式。通过在函数声明前添加async关键字,我们可以在生成器中使用await

async function* generateSequence(start, end) {
  for (let i = start; i <= end; i++) {
    await new Promise(resolve => setTimeout(resolve, 1000));
    yield i;
  }
}

(async () => {
  let generator = generateSequence(1, 5);
  for await (let value of generator) {
    console.log(value); // 1, 2, 3, 4, 5 (每秒一个)
  }
})();

异步生成器会自动处理Promise,使代码更加简洁易读。

实际应用:分页API调用

让我们看一个实际应用场景:处理分页API。假设我们需要从GitHub获取某个仓库的所有提交记录,但API每次只返回一页数据(例如30条记录)。

async function* fetchCommits(repo) {
  let url = `https://api.github.com/repos/${repo}/commits`;
  
  while (url) {
    const response = await fetch(url, {
      headers: {'User-Agent': 'Our script'}
    });
    
    const body = await response.json();
    
    // 从Link头获取下一页URL
    let nextPage = response.headers.get('Link').match(/<(.*?)>; rel="next"/);
    url = nextPage && nextPage[1];
    
    for (let commit of body) {
      yield commit;
    }
  }
}

使用这个异步生成器,我们可以轻松遍历所有提交记录:

(async () => {
  let count = 0;
  
  for await (const commit of fetchCommits('user/repo')) {
    console.log(commit.author.login);
    
    if (++count === 100) break; // 只获取前100条
  }
})();

关键区别总结

| 特性 | 同步 | 异步 | |------|------|------| | 迭代器方法 | Symbol.iterator | Symbol.asyncIterator | | next()返回值 | {value, done} | Promise解析为{value, done} | | 循环语法 | for...of | for await...of | | 生成器声明 | function* | async function* |

注意事项

  1. 扩展运算符(...)不能用于异步迭代器
  2. 异步迭代器与同步迭代器不兼容
  3. 某些内置方法(如Array.from)不支持异步迭代

浏览器中的Streams API

值得注意的是,浏览器提供了专门的Streams API来处理数据流。虽然异步迭代器可以用于类似场景,但Streams API提供了更丰富的功能,如:

  • 转换流(TransformStream)
  • 管道连接(pipeThrough)
  • 更精细的流量控制

结语

异步迭代器和生成器为处理异步数据流提供了优雅的解决方案。它们特别适合以下场景:

  1. 分页API调用
  2. 大文件流式处理
  3. 实时数据流(如WebSocket)
  4. 任何需要逐步处理的数据源

掌握这些概念将大大提升你处理异步数据的能力,使代码更加清晰和易于维护。

ru.javascript.info Современный учебник JavaScript ru.javascript.info 项目地址: https://gitcode.com/gh_mirrors/ru/ru.javascript.info

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

叶彩曼Darcy

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

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

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

打赏作者

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

抵扣说明:

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

余额充值