ES2018 新特征之:异步迭代器 for-await-of

2024-01-22 03:48

本文主要是介绍ES2018 新特征之:异步迭代器 for-await-of,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1. 概述

在 ECMAScript 2015(ES6) 中 JavaScript 引入了迭代器接口(iterator)用来遍历数据。迭代器对象知道如何每次访问集合中的一项, 并跟踪该序列中的当前位置。在 JavaScript 中迭代器是一个对象,它提供了一个 next() 方法,用来返回序列中的下一项。这个方法返回包含两个属性:done 和 value

迭代器对象一旦被创建,就可以反复调用 next()

function makeIterator(array) {let nextIndex = 0;  // 初始索引// 返回一个迭代器对象,对象的属性是一个 next 方法return {next: function() {if (nextIndex < array.length) {// 当没有到达末尾时,返回当前值,并把索引加1return { value: array[nextIndex++], done: false };}// 到达末尾,done 属性为 truereturn {done: true};}};
}

一旦初始化,next() 方法可以用来依次访问对象中的键值:

const it = makeIterator(['j', 'u', 's', 't']);
it.next().value;  // j
it.next().value;  // u
it.next().value;  // s
it.next().value;  // t
it.next().value;  // undefined
it.next().done;   // true
it.next().value;  // undefined

2. 可迭代对象

一个定义了迭代行为的对象,比如在 for...of 中循环了哪些值。为了实现可迭代,一个对象必须实现 @@iterator 方法,这意味着这个对象(或其原型链中的一个对象)必须具有带 Symbol.iterator 键的属性:

StringArrayTypedArrayMap 和 Set 都内置可迭代对象,因为它们的原型对象都有一个 Symbol.iterator 方法。

const justjavac = {[Symbol.iterator]: () => {const items = [`j`, `u`, `s`, `t`, `j`, `a`, `v`, `a`, `c`];return {next: () => ({done: items.length === 0,value: items.shift()})}}
}

当我们定义了可迭代对象后,就可以在 Array.fromfor...of 中使用这个对象:

[...justjavac];
// ["j", "u", "s", "t", "j", "a", "v", "a", "c"]Array.from(justjavac)
// ["j", "u", "s", "t", "j", "a", "v", "a", "c"]new Set(justjavac);
// {"j", "u", "s", "t", "a", "v", "c"}for (const item of justjavac) {console.log(item)
}
// j 
// u 
// s 
// t 
// j 
// a 
// v 
// a 
// c

3. 同步迭代

由于在迭代器方法返回时,序列中的下一个值和数据源的 "done" 状态必须已知,所以迭代器只适合于表示同步数据源。

虽然 JavaScript 程序员遇到的许多数据源是同步的(比如内存中的列表和其他数据结构),但是其他许多数据源却不是。例如,任何需要 I/O 访问的数据源通常都会使用基于事件的或流式异步 API 来表示。不幸的是,迭代器不能用来表示这样的数据源。

(即使是 promise 的迭代器也是不够的,因为它的 value 是异步的,但是迭代器需要同步确定 "done" 状态。)

为了给异步数据源提供通用的数据访问协议,我们引入了 AsyncIterator 接口,异步迭代语句(for-await-of)和异步生成器函数。

4. 异步迭代器

一个异步迭代器就像一个迭代器,除了它的 next() 方法返回一个 { value, done } 的 promise。如上所述,我们必须返回迭代器结果的 promise,因为在迭代器方法返回时,迭代器的下一个值和“完成”状态可能未知。

我们修改一下之前的代码:

 const justjavac = {
-  [Symbol.iterator]: () => {
+  [Symbol.asyncIterator]: () => {const items = [`j`, `u`, `s`, `t`, `j`, `a`, `v`, `a`, `c`];return {
-      next: () => ({
+      next: () => Promise.resolve({done: items.length === 0,value: items.shift()})}}}

好的,我们现在有了一个异步迭代器,代码如下:

const justjavac = {[Symbol.asyncIterator]: () => {const items = [`j`, `u`, `s`, `t`, `j`, `a`, `v`, `a`, `c`];return {next: () => Promise.resolve({done: items.length === 0,value: items.shift()})}}
}

我们可以使用如下代码进行遍历:

for await (const item of justjavac) {console.log(item)
}

如果你遇到了 SyntaxError: for await (... of ...) is only valid in async functions and async generators 错误,那是因为 for-await-of 只能在 async 函数或者 async 生成器里面使用。

修改一下:

(async function(){for await (const item of justjavac) {console.log(item)}
})();

5. 同步迭代器 vs 异步迭代器

5.1 Iterators

// 迭代器
interface Iterator {next(value) : IteratorResult;[optional] throw(value) : IteratorResult;[optional] return(value) : IteratorResult;
}// 迭代结果
interface IteratorResult {value : any;done : bool;
}

5.2 Async Iterators

// 异步迭代器
interface AsyncIterator {next(value) : Promise<IteratorResult>;[optional] throw(value) : Promise<IteratorResult>;[optional] return(value) : Promise<IteratorResult>;
}// 迭代结果
interface IteratorResult {value : any;done : bool;
}

6. 异步生成器函数

异步生成器函数与生成器函数类似,但有以下区别:

  • 当被调用时,异步生成器函数返回一个对象,"async generator",含有 3 个方法(nextthrow,和return),每个方法都返回一个 Promise,Promise 返回 { value, done }。而普通生成器函数并不返回 Promise,而是直接返回 { value, done }。这会自动使返回的异步生成器对象具有异步迭代的功能。
  • 允许使用 await 表达式和 for-await-of 语句。
  • 修改了 yield* 的行为以支持异步迭代。

示例:

async function* readLines(path) {let file = await fileOpen(path);try {while (!file.EOF) {yield await file.readLine();}} finally {await file.close();}
}

函数返回一个异步生成器(async generator)对象,可以用在 for-await-of 语句中。

7. 实现

  • Chakra - 暂未支持
  • JavaScriptCore - Safari Tech Preview 40
  • SpiderMonkey - Firefox 57
  • V8 - Chrome 63

Polyfills

Facebook 的 Regenerator 项目为 AsyncIterator 接口提供了一个 polyfill,将异步生成器函数变成返回 AsyncIterator的对象 ECMAScript 5 函数。Regenerator 还不支持 for-await-of 异步迭代语法。

Babylon parser 项目支持异步生成器函数和 for- await-of 语句(v6.8.0+)。你可以使用它的 asyncGenerators 插件。

require("babylon").parse("code", {sourceType: "module",plugins: ["asyncGenerators"]
});

另外,从 6.16.0 开始,异步迭代被包含在 Babel 的 "babel-plugin-transform-async-generator-functions" 下以及 babel-preset-stage-3

require("babel-core").transform("code", {plugins: ["transform-async-generator-functions"]
});
  •  
  •  

这篇关于ES2018 新特征之:异步迭代器 for-await-of的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/631769

相关文章

迭代器模式iterator

学习笔记,原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 (列表、 栈和树等) 的情况下遍历集合中所有的元素

js异步提交form表单的解决方案

1.定义异步提交表单的方法 (通用方法) /*** 异步提交form表单* @param options {form:form表单元素,success:执行成功后处理函数}* <span style="color:#ff0000;"><strong>@注意 后台接收参数要解码否则中文会导致乱码 如:URLDecoder.decode(param,"UTF-8")</strong></span>

OmniGlue论文详解(特征匹配)

OmniGlue论文详解(特征匹配) 摘要1. 引言2. 相关工作2.1. 广义局部特征匹配2.2. 稀疏可学习匹配2.3. 半稠密可学习匹配2.4. 与其他图像表示匹配 3. OmniGlue3.1. 模型概述3.2. OmniGlue 细节3.2.1. 特征提取3.2.2. 利用DINOv2构建图形。3.2.3. 信息传播与新的指导3.2.4. 匹配层和损失函数3.2.5. 与Super

多线程篇(阻塞队列- LinkedBlockingDeque)(持续更新迭代)

目录 一、LinkedBlockingDeque是什么 二、核心属性详解 三、核心方法详解 addFirst(E e) offerFirst(E e) putFirst(E e) removeFirst() pollFirst() takeFirst() 其他 四、总结 一、LinkedBlockingDeque是什么 首先queue是一种数据结构,一个集合中

AsyncTask 异步任务解析

1:构建AsyncTask 子类的回调方法: A:doInBackground:   必须重写,所有的耗时操作都在这个里面进行; B: onPreExecute:     用户操作数据前的调用; 例如:显示一个进度条 等 ; C: onPostExecute:    当doInBackground 执行完成后;会自动把数据传给onPostExecute方法;也就是说:这个方法是处理返回的数据的方法

《计算机视觉工程师养成计划》 ·数字图像处理·数字图像处理特征·概述~

1 定义         从哲学角度看:特征是从事物当中抽象出来用于区别其他类别事物的属性集合,图像特征则是从图像中抽取出来用于区别其他类别图像的属性集合。         从获取方式看:图像特征是通过对图像进行测量或借助算法计算得到的一组表达特性集合的向量。 2 认识         有些特征是视觉直观感受到的自然特征,例如亮度、边缘轮廓、纹理、色彩等。         有些特征需要通

多线程篇(阻塞队列- LinkedBlockingQueue)(持续更新迭代)

目录 一、基本概要 1. 构造函数 2. 内部成员 二、非阻塞式添加元素:add、offer方法原理 offer的实现 enqueue入队操作 signalNotEmpty唤醒 删除线程(如消费者线程) 为什么要判断if (c == 0)时才去唤醒消费线程呢? 三、阻塞式添加元素:put 方法原理 图解:put线程的阻塞过程 四、非阻塞式移除:poll方法原理 dequ

HalconDotNet中的图像特征与提取详解

文章目录 简介一、边缘特征提取二、角点特征提取三、区域特征提取四、纹理特征提取五、形状特征提取 简介   图像特征提取是图像处理中的一个重要步骤,用于从图像中提取有意义的特征,以便进行进一步的分析和处理。HalconDotNet提供了多种图像特征提取方法,每种方法都有其特定的应用场景和优缺点。 一、边缘特征提取   边缘特征提取是图像处理中最基本的特征提取方法之一,通过检

使用Node-API进行异步任务开发

一、Node-API异步任务机制概述         Node-API异步任务开发主要用于执行耗时操作的场景中使用,以避免阻塞主线程,确保应用程序的性能和响应效率。         1、应用场景: 文件操作:读取大型文件或执行复杂的文件操作时,可以使用异步工作项来避免阻塞主线程。网络请求:当需要进行网络请求并等待响应时,可以使用异步工作项来避免阻塞主线程,从而提高应用程序的响应性能。数据库操

六、我们应当怎样做需求调研:迭代

前面我一直在反复强调这样一个观点,需求分析不是一蹴而就的,是一个反复迭代的过程。它将从第一次需求分析开始,一直持续到整个项目生命周期。为什么这样说呢?让我们一起来分析分析。  在第一次的需求分析阶段,我们在一段时期内需要与客户进行反复地讨论,这个过程往往是这样一个反复循环的过程:需求捕获->需求整理->需求验证->再需求捕获••••••  需求捕获,就是我们与客户在一起开研讨会