详解ES9中的新特性Async iteration

详解ES9中的新特性Async iteration

在ES6中,引入了同步iteration的概念,随着ES8中的Async操作符的引用,是不是可以在一异步操作中进行遍历操作呢?

今天要给大家讲一讲ES9中的异步遍历新特性Async iteration

异步遍历

在讲解异步遍历之前,我们先回想一下ES6中的同步遍历。

根据ES6的定义,iteration主要由三部分组成:

1、Iterable

先看下Iterable的定义:

interface Iterable {    [Symbol.iterator]() : Iterator;}

登录后复制

Iterable表示这个对象里面有可遍历的数据,并且需要实现一个可以生成Iterator的工厂方法。

2、Iterator

interface Iterator {    next() : IteratorResult;}

登录后复制

可以从Iterable中构建Iterator。Iterator是一个类似游标的概念,可以通过next访问到IteratorResult。

3、IteratorResult

IteratorResult是每次调用next方法得到的数据。

interface IteratorResult {    value: any;    done: boolean;}

登录后复制

IteratorResult中除了有一个value值表示要获取到的数据之外,还有一个done,表示是否遍历完成。

下面是一个遍历数组的例子:

> const iterable = ['a', 'b'];> const iterator = iterable[Symbol.iterator]();> iterator.next(){ value: 'a', done: false }> iterator.next(){ value: 'b', done: false }> iterator.next(){ value: undefined, done: true }

登录后复制

但是上的例子遍历的是同步数据,如果我们获取的是异步数据,比如从http端下载下来的文件,我们想要一行一行的对文件进行遍历。因为读取一行数据是异步操作,那么这就涉及到了异步数据的遍历。

加入异步读取文件的方法是readLinesFromFile,那么同步的遍历方法,对异步来说就不再适用了:

//不再适用for (const line of readLinesFromFile(fileName)) {    console.log(line);}

登录后复制

也许你会想,我们是不是可以把异步读取一行的操作封装在Promise中,然后用同步的方式去遍历呢?

想法很好,不过这种情况下,异步操作是否执行完毕是无法检测到的。所以方法并不可行。

于是ES9引入了异步遍历的概念:

可以通过Symbol.asyncIterator来获取到异步iterables中的iterator。

异步iterator的next()方法返回Promises对象,其中包含IteratorResults。

所以,我们看下异步遍历的API定义:

interface AsyncIterable {    [Symbol.asyncIterator]() : AsyncIterator;}interface AsyncIterator {    next() : Promise;}interface IteratorResult {    value: any;    done: boolean;}

登录后复制

我们看一个异步遍历的应用:

const asyncIterable = createAsyncIterable(['a', 'b']);const asyncIterator = asyncIterable[Symbol.asyncIterator]();asyncIterator.next().then(iterResult1 => {    console.log(iterResult1); // { value: 'a', done: false }    return asyncIterator.next();}).then(iterResult2 => {    console.log(iterResult2); // { value: 'b', done: false }    return asyncIterator.next();}).then(iterResult3 => {    console.log(iterResult3); // { value: undefined, done: true }});

登录后复制

其中createAsyncIterable将会把一个同步的iterable转换成一个异步的iterable,我们将会在下面一小节中看一下到底怎么生成的。

这里我们主要关注一下asyncIterator的遍历操作。

因为ES8中引入了Async操作符,我们也可以把上面的代码,使用Async函数重写:

async function f() {    const asyncIterable = createAsyncIterable(['a', 'b']);    const asyncIterator = asyncIterable[Symbol.asyncIterator]();    console.log(await asyncIterator.next());        // { value: 'a', done: false }    console.log(await asyncIterator.next());        // { value: 'b', done: false }    console.log(await asyncIterator.next());        // { value: undefined, done: true }}

登录后复制

异步iterable的遍历

使用for-of可以遍历同步iterable,使用 for-await-of 可以遍历异步iterable。

async function f() {    for await (const x of createAsyncIterable(['a', 'b'])) {        console.log(x);    }}// Output:// a// b

登录后复制

注意,await需要放在async函数中才行。

如果我们的异步遍历中出现异常,则可以在 for-await-of 中使用try catch来捕获这个异常:

function createRejectingIterable() {    return {        [Symbol.asyncIterator]() {            return this;        },        next() {            return Promise.reject(new Error('Problem!'));        },    };}(async function () {     try {        for await (const x of createRejectingIterable()) {            console.log(x);        }    } catch (e) {        console.error(e);            // Error: Problem!    }})();

登录后复制

同步的iterable返回的是同步的iterators,next方法返回的是{value, done}。

如果使用 for-await-of 则会将同步的iterators转换成为异步的iterators。然后返回的值被转换成为了Promise。

如果同步的next本身返回的value就是Promise对象,则异步的返回值还是同样的promise。

也就是说会把:Iterable> 转换成为 AsyncIterable ,如下面的例子所示:

async function main() {    const syncIterable = [        Promise.resolve('a'),        Promise.resolve('b'),    ];    for await (const x of syncIterable) {        console.log(x);    }}main();// Output:// a// b

登录后复制

上面的例子将同步的Promise转换成异步的Promise。

async function main() {    for await (const x of ['a', 'b']) {        console.log(x);    }}main();// Output:// c// d

登录后复制

上面的例子将同步的常量转换成为Promise。 可以看到两者的结果是一样的。

异步iterable的生成

回到上面的例子,我们使用createAsyncIterable(syncIterable)将syncIterable转换成了AsyncIterable。

我们看下这个方法是怎么实现的:

async function* createAsyncIterable(syncIterable) {    for (const elem of syncIterable) {        yield elem;    }}

登录后复制

上面的代码中,我们在一个普通的generator function前面加上async,表示的是异步的generator。

对于普通的generator来说,每次调用next方法的时候,都会返回一个object {value,done} ,这个object对象是对yield值的封装。

对于一个异步的generator来说,每次调用next方法的时候,都会返回一个包含object {value,done} 的promise对象。这个object对象是对yield值的封装。

因为返回的是Promise对象,所以我们不需要等待异步执行的结果完成,就可以再次调用next方法。

我们可以通过一个Promise.all来同时执行所有的异步Promise操作:

const asyncGenObj = createAsyncIterable(['a', 'b']);const [{value:v1},{value:v2}] = await Promise.all([    asyncGenObj.next(), asyncGenObj.next()]);console.log(v1, v2); // a b

登录后复制

在createAsyncIterable中,我们是从同步的Iterable中创建异步的Iterable。

接下来我们看下如何从异步的Iterable中创建异步的Iterable。

从上一节我们知道,可以使用for-await-of 来读取异步Iterable的数据,于是我们可以这样用:

async function* prefixLines(asyncIterable) {    for await (const line of asyncIterable) {        yield '> ' + line;    }}

登录后复制

在generator一文中,我们讲到了在generator中调用generator。也就是在一个生产器中通过使用yield*来调用另外一个生成器。

同样的,如果是在异步生成器中,我们可以做同样的事情:

async function* gen1() {    yield 'a';    yield 'b';    return 2;}async function* gen2() {    const result = yield* gen1();         // result === 2}(async function () {    for await (const x of gen2()) {        console.log(x);    }})();// Output:// a// b

登录后复制

如果在异步生成器中抛出异常,这个异常也会被封装在Promise中:

async function* asyncGenerator() {    throw new Error('Problem!');}asyncGenerator().next().catch(err => console.log(err)); // Error: Problem!

登录后复制

异步方法和异步生成器

异步方法是使用async function 声明的方法,它会返回一个Promise对象。

function中的return或throw异常会作为返回的Promise中的value。

(async function () {    return 'hello';})().then(x => console.log(x)); // hello(async function () {    throw new Error('Problem!');})().catch(x => console.error(x)); // Error: Problem!

登录后复制

异步生成器是使用 async function * 申明的方法。它会返回一个异步的iterable。

通过调用iterable的next方法,将会返回一个Promise。异步生成器中yield 的值会用来填充Promise的值。如果在生成器中抛出了异常,同样会被Promise捕获到。

async function* gen() {    yield 'hello';}const genObj = gen();genObj.next().then(x => console.log(x));    // { value: 'hello', done: false }

登录后复制

本文作者:flydean程序那些事本文链接:http://www.flydean.com/es9-async-iteration/

更多编程相关知识,请访问:编程视频!!

以上就是详解ES9中的新特性Async iteration的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2714462.html

(0)
上一篇 2025年3月7日 21:33:56
下一篇 2025年3月7日 18:08:32

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • php7新特性的比较和理解

    1.null合并运算符(??)     ??语法: 如果变量存在且值不为null,它就会返回自身的值,否则返回它的第二个操作数. //php7以前  if判断if(empty($_GET[‘param’])) {      $param =…

    2025年3月5日
    200
  • EF Core 2.0 新特性

    前言 目前 EF Core 的最新版本为 2.0.0-priview1-final,所以本篇文章主要是针对此版本的一些说明。 注意:如果你要在Visual Studio 中使用 .NET Core 2.0 , 你需要至少 Visual St…

    编程技术 2025年3月5日
    200
  • go语言有什么新特性

    go语言的新特性有:1、Go模块,用于管理Go语言项目的依赖关系;2、错误处理,增加了一个新的错误类型error,使得错误处理更加灵活和简洁;3、上下文包,用于在goroutine之间传递请求范围的值;4、嵌入,即一个结构体可以嵌入到另一个…

    2025年3月1日
    200
  • golang泛型的特点和限制:探索值得的新特性

    golang泛型的优势和限制:值得一试的新特性,需要具体代码示例 摘要:Golang是一种强类型的静态语言,一直以来,其缺乏泛型特性一直备受争议。然而,近期Golang开发团队正积极推进泛型特性的引入,以提供更高的代码复用性和可读性。本文将…

    2025年3月1日
    200
  • Go语言新特性解读:让编程更高效

    【Go语言新特性解读:让编程更高效,需要具体代码示例】 近年来,Go语言在软件开发领域备受关注,其简洁、高效的设计理念吸引了越来越多的开发者。作为一种静态类型的编程语言,Go语言不断推出新的特性以提高开发效率,简化代码编写过程。本文将深入解…

    2025年3月1日
    200
  • 掌握Go语言最新特性,迎接编程挑战

    Go语言作为一门高效、简洁、易学的编程语言,在软件开发领域备受关注。随着Go语言的不断发展,新的特性和功能不断被引入,为开发者们提供了更多的技术选择和优化方案。本篇文章将重点介绍Go语言最新的特性,为读者们提供具体的代码示例,帮助大家更好地…

    2025年3月1日
    200
  • golang 最新引入了哪些关键特性?

    go语言的最新关键特性包括:泛型,提高代码可重用性。误差处理改进,支持自定义错误类型。时区支持,简化跨时区工作。开发工具链改进,提供更快速的模块依赖解析。控制流改进,添加了fallthrough语句。 Go 语言中的最新关键特性 Go 语言…

    2025年3月1日
    200
  • Python 3.x 新特性及10大变化

    python 3.x 起始版本是python 3.0,目前的最新版本是 3.3.3 Python之父Guido van Rossum谈到了Python 3.0的构思: 一直以来,除非要打破向后兼容性,否则很多缺陷和错误都无法修复。因此,Py…

    编程技术 2025年2月28日
    200
  • numpy版本更新解读:新特性与改进的性能

    随着数据科学和深度学习的不断发展,Python作为主流的编程语言之一,其科学计算库numpy也在不断推陈出新。最近,numpy发布了新的版本,其中包含了一些新特性和性能改进。在这篇文章中,我们将深入探讨numpy的新版本,介绍其中一些重要的…

    2025年2月26日
    200
  • 了解PHP8中的新特性,让你的编程变得更加简单

    随着时间的推移,php编程语言也在不断的发展和完善。最新的php 8版本中,添加了许多新的功能和特性,这些功能可以提高开发人员的生产力,简化代码,增强代码的可读性和可维护性。在这篇文章中,我们将介绍php8中5个最重要的新特性。 JIT编译…

    编程技术 2025年2月25日
    200

发表回复

登录后才能评论