视频讲解

前往原文 前端Tips 专栏#6,点击观看

文字讲解

本期主要是讲解如何使用 for-await-of 语法糖进行异步操作迭代,让组织异步操作的代码更加简洁易读。

1、场景简述

以下代码中的 for...of 操作,打印顺序 "2、3、4"(总共耗费时间 4s):

const delay = (time) => () => setTimeout(() => { console.log(time) }, time * 1000);

const delays = [delay(3), delay(2), delay(4)];

for (cur of delays) {
cur();
}

但我们想要以数组顺序打印 “3、2、4”(总共耗时9s),请问该如何实现?

2、同步迭代器

以常见的数组打印为例,下述代码会依次打印出 "0、1":

for(const cur of [0, 1]){
console.log(cur);
}

那么如何用 同步迭代器 实现上述同等输出?

Iterator 是 ECMAScript 2015 引进的功能,它就是一个 function,只不过对这个 function 的形式有特殊的规定:

  1. 返回对象必须包含 next 属性,该属性也是 function
  2. next 函数返回值必须返回包含 donevalue 这两个字段的对象

有了 Iterator,就可以借助 [Symbol.iterator] 构造出 可迭代对象(Iteratable)

// 返回一个可迭代对象,注意 [Symbol.iterator] 这个 key
const someIteratable = {
[Symbol.iterator]: someIterator
}

凡是可迭代对象就可以使用 for...of 语法,所以这是一种层层迭进的关系。

3、使用迭代器实现数组打印

知道了迭代器的概念后,就可以借助迭代器实现上述的数组打印功能,首先自定义构造出 countIterator 迭代器

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

然后创建出可迭代对象,由于该对象的行为和 [0,1] 这个数组类似,所以起名为 customArray

// 返回一个可迭代对象,注意 [Symbol.iterator] 这个 key
const customArray = {
[Symbol.iterator]: countIterator
}

最后给这个可迭代对象应用 for...of 即可,就能打印出 0、1 内容:

for (const cur of customArray) {
console.log(cur)
}

通过这个例子你就应该比较容易迭代器的理解,其实 JS 原生的StringArrayMapSet 等都是可迭代对象,因为它们的原型对象都有一个 Symbol.iterator 方法

4、异步迭代器

理解了同步迭代器,那么 异步迭代器(Async Iterator)也就很容易理解了,它和同步迭代器的差别在于:

  1. 异步迭代器必须返回 Promise 对象,且该 Promise 返回 { value, done } 格式对象
  2. 异步可迭代对象(Async Iteratable)用 Symbol.asyncIterator 作为 key
  3. 异步可迭代对象(Async Iteratable)可用 for-await-of 进行迭代

Async iterator 是 ECMAScript 2018 引进的

借助异步迭代器就可以实现本期开头所讲的功能,实现自定义的 delayIteraterable 可迭代对象,它使用 [Symbol.asyncIterator] 作为 key,其 value 就是异步迭代器:

const promisify = func => (...args) =>
new Promise((resolve, reject) =>
func(...args, (err, result) => (err ? reject(err) : resolve(result)))
); const delayIteraterable = {
[Symbol.asyncIterator]: () => {
return {
next: () => {
const cur = promisify(delays.shift());
return cur().then(res => {
return {
done: delays.length === 0,
value: res
}
});
}
}
}
}

这里用到的 promisify 函数,具体可参考前端 Tips - 第 5 期的内容讲解。

然后直接搭配 for-await-of 语法糖使用,就能进行异步迭代,按我们的要求依次输出 “3、2、4”(总共耗时9s)

const execIt = async function () {
for await (const cur of delayIteraterable) {
console.log(cur);
}
}
execIt();

5、扩展:Generator & Async Generator

除了用迭代器生成 可迭代对象 外,还能用 Generator(生成器)生成 可迭代对象,而且一般来讲代码实现也更为紧凑。

由于时间关系就不展开了,感兴趣的可阅读文末的参考文章自行学习。本期的例子也提供了 generator 的版本可供参考,链接:https://github.com/boycgit/fe-program-tips/blob/master/src/6-async-iterator/async-yield.js

6、参考文档

附:如何获取往期 “前端Tips” 列表

有两种方式获取历史 tips:

① 在公众号内回“tips” + “年份” + “A(或者B)” 获取半年度 tips。例如:回复 “tips2020A” 即可获取 2020 年上半年 tips 列表

② 前往网站:https://boycgit.github.io/fe-program-tips ,里面提供了搜索功能

欢迎大家关注我的知识专栏,更多内容等你来挖掘

「可在微信内搜索 “JSCON简时空”或 “iJSCON” 关注」

前端Tips#6 - 在 async iterator 上使用 for-await-of 语法糖的更多相关文章

  1. 前端Tips#2 - 将 arguments 转换成Array的最佳实践

    本文同步自 JSCON简时空 - 技术博客,点击阅读 视频讲解 文字讲解 1.先讲结论 有很多种方式将 arguments 转换成数组,那么哪一种方式是最优的? 为节约大伙儿的时间,这里先说一下结论: ...

  2. 前端Tips#3 - 简写的 border-radius 100% 和 50% 是等效的

    本文同步自 JSCON简时空 - 技术博客,点击阅读 视频讲解 视频地址 文字讲解 1.先讲结论 border-radius 这个 css 属性大家应该使用得非常娴熟,现实中用到的场景基本都是四个圆角 ...

  3. 前端Tips#4 - 用 process.hrtime 获取纳秒级的计时精度

    本文同步自 JSCON简时空 - 前端Tips 专栏#4,点击阅读 视频讲解 视频地址 文字讲解 如果去测试代码运行的时长,你会选择哪个时间函数? 一般第一时间想到的函数是 Date.now 或 Da ...

  4. ES7中前端异步特性:async、await。

    在最新的ES7(ES2017)中提出的前端异步特性:async.await. 什么是async.await? async顾名思义是"异步"的意思,async用于声明一个函数是异步的 ...

  5. 使用Ajax+jQuery来实现前端收到的数据在console上显示+简单的主页设计与bootstrap插件实现图片轮播

    1.实现前端输入的数据在console上显示 上一篇是解决了在前端的输入信息在cygwin上显示,这次要给前台们能看见的数据,因为数据库里插入的数据少,所以写的语句翻来覆去就那几个词,emmm···当 ...

  6. 用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面

    用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面 1.什么是跨域以及产生原因 跨域是指a页面想获取b页面资源,如果a.b页面的协议.域名.端口.子域名不同,或是a页面为ip地 ...

  7. Angular14 利用Angular2实现文件上传的前端、利用springBoot实现文件上传的后台、跨域问题

    一.angular2实现文件上传前端 Angular2使用ng2-file-upload上传文件,Angular2中有两个比较好用的上传文件的第三方库,一个是ng2-file-upload,一个是ng ...

  8. Spring @async 方法上添加该注解实现异步调用的原理

    Spring @async 方法上添加该注解实现异步调用的原理 学习了:https://www.cnblogs.com/shangxiaofei/p/6211367.html 使用异步方法进行方法调用 ...

  9. 【转】剖析异步编程语法糖: async和await

    一.难以被接受的async 自从C#5.0,语法糖大家庭又加入了两位新成员: async和await. 然而从我知道这两个家伙之后的很长一段时间,我甚至都没搞明白应该怎么使用它们,这种全新的异步编程模 ...

随机推荐

  1. 84)PHP,SQL注入基础讲解

     怎么预防: 填写防止SQL注入的代码:

  2. 方差分析||MSA/MSE|

    应用统计学-方差分析 数值型数据使用线性回归来研究因素对因变量的影响.类别型数据使用方差分析来研究因素对因变量的影响.方差分析是使用方差比MSA/MSE来检验均值是否全相等,即相等是H0假设,而不全相 ...

  3. python使用geopandas和shapely处理shp文件

    一.环境搭建 所需库:geopandas (以及前置库)  doc:http://geopandas.org/ shapely(以及前置库)  doc: 二.数据预处理 1.将shp文件进行切片 2. ...

  4. verilog求倒数-ROM实现方法

    采用线性逼近法结合32段线性查找表的方式来实现1/z的计算. 首先将1/32-1/64的定点化数据存放到ROM中,ROM中存放的是扩大了2^20 次方的数字四舍五入后的整数部分.n值越大,精度越大,误 ...

  5. Android Studio调用系统隐藏接口EthernetManager

    google source签名文件参考:https://android.googlesource.com/platform/build/+/donut-release/target/product/s ...

  6. JavaScript replace() 方法+字符子集介绍(*)

    重点两部分知识点 1.javascript replace()函数用法 以下replace用法转载自w3cSchool:http://www.w3school.com.cn/jsref/jsref_r ...

  7. Java web期末项目第一阶段成果发表

    摘要 我们做的系统是一个基于Java web与MySQL的食堂订餐系统 班级: 计科二班 小组成员:李鉴宣.袁超 我们的第一阶段主要完成以下三件事: 完成项目的需求分析 完成项目的领域逻辑(domai ...

  8. yii2.0 集合七牛SDK 上传图片到第三方

    首先,请用composer下载七牛phpSDK (具体参考官方文档) composer require qiniu/php-sdk 注册七牛账号 获取 AK SK(密匙) ,创建资源对象 获取doma ...

  9. python Select\Poll\Epoll异步IO与事件驱动

    参考:http://www.cnblogs.com/alex3714/articles/5248247.html 写服务器处理模型的程序时通常采用的模型: (1)每收到一个请求,创建一个新的进程,来处 ...

  10. Python---5Python内置的有序集合-list和tuple

    list Python内置的一种数据类型是列表:list,[ ].可以修改的集合. list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出班里所有同学的名字,就可以用一个list表示: ...