博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ES2018 新特征之:异步迭代器 for-await-of
阅读量:6264 次
发布时间:2019-06-22

本文共 4424 字,大约阅读时间需要 14 分钟。

ES2018 新特性

  • 异步迭代器(本文)

1. 概述

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

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

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

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

const it = makeIterator(['j', 'u', 's', 't']);it.next().value;  // jit.next().value;  // uit.next().value;  // sit.next().value;  // tit.next().value;  // undefinedit.next().done;   // trueit.next().value;  // undefined

2. 可迭代对象

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

StringArrayTypedArrayMapSet 都内置可迭代对象,因为它们的原型对象都有一个 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
; [optional] throw(value) : Promise
; [optional] return(value) : Promise
;}// 迭代结果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. 实现

  • - 暂未支持
  • - Safari Tech Preview 40
  • - Firefox 57
  • - Chrome 63

Polyfills

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

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

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

另外,从 6.16.0 开始,异步迭代被包含在 Babel 的 下以及 。

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

转载地址:http://nucpa.baihongyu.com/

你可能感兴趣的文章
POJ1811_Prime Test【Miller Rabin素数測试】【Pollar Rho整数分解】
查看>>
ConnectString中enlist设置的含义
查看>>
潜移默化学会WPF(企业经验篇)--Log4Net(二)
查看>>
轻量级面向SQL的MySQL开源监控工具
查看>>
ubuntu 卸载 程序软件
查看>>
iOS 6,5支持 portrait,landscape (横竖屏的处理)
查看>>
FineUI v3.2.2发布了!(7 天后再出新版,给不给力?)
查看>>
Quartz在Spring中动态设置cronExpression (spring设置动态定时任务)------转帖
查看>>
vb webbrower 相对坐标
查看>>
原始的js代码和jquery对比
查看>>
.net和java和谐相处之安卓客户端+.net asp.net mvc webapi 2
查看>>
Dynamic CRM 2013学习笔记(十六)用JS控制Tab可见,可用
查看>>
jquery对象和javascript对象相互转换
查看>>
laravel开启调试模式
查看>>
Spring aop的实现原理
查看>>
ADO.NET一小记-select top 参数问题
查看>>
(转)jquery easyui treegrid使用小结 (主要讲的是如何编辑easyui中的行信息包括添加 下拉列表等)...
查看>>
iOS使用宏写单例
查看>>
Isotig & cDNA & gene structure & alternative splicing & gene loci & 表达谱
查看>>
3、Cocos2dx 3.0游戏开发找小三之搭建开发环境
查看>>