前端Tips#6 - 在 async iterator 上使用 for-await-of 语法糖
视频讲解
前往原文 前端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 的形式有特殊的规定:
- 返回对象必须包含 
next属性,该属性也是function - 该 
next函数返回值必须返回包含done和value这两个字段的对象 
有了 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 原生的String、Array、Map 和 Set 等都是可迭代对象,因为它们的原型对象都有一个 Symbol.iterator 方法。
4、异步迭代器
理解了同步迭代器,那么 异步迭代器(Async Iterator)也就很容易理解了,它和同步迭代器的差别在于:
- 异步迭代器必须返回 Promise 对象,且该 Promise 返回 
{ value, done }格式对象 - 异步可迭代对象(Async Iteratable)用 Symbol.asyncIterator 作为 key
 - 异步可迭代对象(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、参考文档
- for await...of:官方 
for await...of教程 - Asynchronous Iterators in JavaScript:通俗易懂的教程,条理清晰
 - ES2018 新特征之:异步迭代器 for-await-of:ES 2018 系列教程中的异步迭代器教程
 - map for async iterators in JavaScript:Youtube 上的教程,使用异步迭代器完成异步 mapper 操作
 
附:如何获取往期 “前端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 语法糖的更多相关文章
- 前端Tips#2 - 将 arguments 转换成Array的最佳实践
		
本文同步自 JSCON简时空 - 技术博客,点击阅读 视频讲解 文字讲解 1.先讲结论 有很多种方式将 arguments 转换成数组,那么哪一种方式是最优的? 为节约大伙儿的时间,这里先说一下结论: ...
 - 前端Tips#3 - 简写的 border-radius 100% 和 50% 是等效的
		
本文同步自 JSCON简时空 - 技术博客,点击阅读 视频讲解 视频地址 文字讲解 1.先讲结论 border-radius 这个 css 属性大家应该使用得非常娴熟,现实中用到的场景基本都是四个圆角 ...
 - 前端Tips#4 - 用 process.hrtime 获取纳秒级的计时精度
		
本文同步自 JSCON简时空 - 前端Tips 专栏#4,点击阅读 视频讲解 视频地址 文字讲解 如果去测试代码运行的时长,你会选择哪个时间函数? 一般第一时间想到的函数是 Date.now 或 Da ...
 - ES7中前端异步特性:async、await。
		
在最新的ES7(ES2017)中提出的前端异步特性:async.await. 什么是async.await? async顾名思义是"异步"的意思,async用于声明一个函数是异步的 ...
 - 使用Ajax+jQuery来实现前端收到的数据在console上显示+简单的主页设计与bootstrap插件实现图片轮播
		
1.实现前端输入的数据在console上显示 上一篇是解决了在前端的输入信息在cygwin上显示,这次要给前台们能看见的数据,因为数据库里插入的数据少,所以写的语句翻来覆去就那几个词,emmm···当 ...
 - 用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面
		
用nginx的反向代理机制解决前端跨域问题在nginx上部署web静态页面 1.什么是跨域以及产生原因 跨域是指a页面想获取b页面资源,如果a.b页面的协议.域名.端口.子域名不同,或是a页面为ip地 ...
 - Angular14 利用Angular2实现文件上传的前端、利用springBoot实现文件上传的后台、跨域问题
		
一.angular2实现文件上传前端 Angular2使用ng2-file-upload上传文件,Angular2中有两个比较好用的上传文件的第三方库,一个是ng2-file-upload,一个是ng ...
 - Spring @async 方法上添加该注解实现异步调用的原理
		
Spring @async 方法上添加该注解实现异步调用的原理 学习了:https://www.cnblogs.com/shangxiaofei/p/6211367.html 使用异步方法进行方法调用 ...
 - 【转】剖析异步编程语法糖: async和await
		
一.难以被接受的async 自从C#5.0,语法糖大家庭又加入了两位新成员: async和await. 然而从我知道这两个家伙之后的很长一段时间,我甚至都没搞明白应该怎么使用它们,这种全新的异步编程模 ...
 
随机推荐
- [LC] 103. Binary Tree Zigzag Level Order Traversal
			
Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ...
 - C++ List的用法
			
Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢. assign() 给list赋值 back() 返回最后一个元素 begin() ...
 - WebService如何根据WSDL文件转换成本地的C#类
			
WebService有两种使用方式,一种是直接通过添加服务引用,另一种则是通过WSDL生成. 添加服务引用大家基本都用过,这里就不讲解了. 那么,既然有直接引用的方式,为什么还要通过WSDL生成呢? ...
 - 疯狂收集个人信息的谷歌,为何不像Facebook那样让人毛骨悚然?
			
自从Facebook信息泄露丑闻事件发生后,互联网上的个人隐私及安全成为大众的"心病".而大众最讨厌的,是互联网企业收集自己的信息,因此都在积极讨伐这种行为.但他们却忘了,收集用户 ...
 - golang seelog使用
			
golang中自带的有log包,但是功能并不能满足我们.很多人推荐seelog,我们今天一起学习下. 安装 go get github.com/cihub/seelog 快速开始 引用seelog w ...
 - java内部类基础知识
			
一.java内部类具体分四大类 1.成员内部类 2.静态内部类 3.局部内部类 4.匿名内部类 1.成员内部类 :作为类的成员,存在于类中 //成员内部类可以调用外部类的所有 ...
 - [洛谷P4782] [模板] 2-SAT 问题
			
NOIp后第一篇题解. NOIp我考的很凉啊...... 题目传送门 之前讲过怎么判断2-SAT是否存在解. 至于如何构造一组解: 我们想到对tarjan缩点后的图进行拓扑排序. 那么对于代表0状态的 ...
 - springboot中使用异步的常用两种方式及其比较
			
一般对于业务复杂的流程,会有一些处理逻辑不需要及时返回,甚至不需要返回值,但是如果充斥在主流程中,占用大量时间来处理,就可以通过异步的方式来优化.实现异步的常用方法远不止两种,但是个人经验常用的,好用 ...
 - Nginx for windows 访问路径包含中文
			
转载自http://blog.csdn.net/five824/article/details/48261213 Nginx for windows 访问路径包含中文 原创 2015年09月07日 0 ...
 - Windows XP系列全下载(均为MSDN原版)
			
正版windows xp sp3 下载大全(附:正版密钥) 微软MSDN Windows XP Professional下载 Windows XP Professional 简体中文 (最原始版本,无 ...