ES6中的迭代器、Generator函数及Generator函数的异步操作方法


Posted in Javascript onMay 12, 2019

最近在写RN相关的东西,其中涉及到了redux-saga ,saga的实现原理就是ES6中的Generator函数,而Generator函数又和迭代器有着密不可分的关系。所以本篇博客先学习总结了iterator相关的东西,然后又介绍了Generator相关的内容,最后介绍了使用Generator进行异步编程。本篇博客所涉及的示例使用TypeScript语言编写,当然所涉及的特性是基于ES6规范的,使用TS语言不影响来阐述和总结ES6的相关特性。下篇博客准备系统梳理一下saga相关的内容。

一、迭代器

之前再聊迭代器模式时,使用Swift语言自定义过迭代器,在TS中也有迭代器。此处的迭代器与之前所介绍的迭代器是大同小异的。首先我们先来自定义一个迭代器,然后再看一下ES6中的迭代器的使用方式。

1、自定义迭代器

下方定义了一个迭代器函数,函数说明如下:

  • 该函数接收一个数组类型的参数,我们可以将需要创建迭代器的数组作为参数传进来。
  • 函数内部定义了一个 nextIndex 参数用来记录迭代器的位置。
  • 该函数返回一个迭代器对象,该迭代器对象包含一个key为 next , value为匿名函数的属性。
  • 这个key为 next 的匿名方法的返回值为每次迭代器的返回结果对象,这个结果对象由 两个属性组成,value表示本次迭代器的值,done表示迭代器遍历是否结束。遍历到最后,最终返回的值为 { value: undefine, done: true }, 也就意味着迭代器遍历结束,value是undefined, done为true。 

 

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

自定义完迭代器后,我们就可以对上述代码进行测试了。

首先创建了一个数组,然后将数组传给 makeIterator 函数。

而 makeIterator 函数会返回一个含有next方法的迭代器对象。

  • 我们将这个迭代器对象命名为 iterator,我们就可以通过 iterator的next方法来依次获取数组中的值了。
  • 我们通过 while 循环来不断的调用 iterator中的next方法,直到next方法返回的对象中的done值为true时,表示遍历结束。
  • 遍历结束后,我们再次调用 next() 方法,得到的是{ value: undefind, done: true } 的对象,表示遍历结束,获取的value值为 undefined。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法2、2。ES6中的迭代器

类似于Swift语言的特性,ES6规范中我们可以直接通过一些对象获取该对象所对应的迭代器,如下所示:

下方示例中使用的数组和上面使用的list是一个,首先我们通过 list[Symbol.iterator]() 的方式获取了 list对应的迭代器。

(Symbol也是一种数据类型, 该数据类型用来表示独一无二的对象)该迭代器的使用方式和输出结果与上述我们自定义的迭代器的使用方式完全一致, 输出结果与之前的结果也是一致的。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

3、使用 for - of 遍历迭代器

上述方式创建的迭代器我们是使用的while循环来进行遍历的,除了while循环,我们还可以通过for-of 进行遍历。

此处的 for - of遍历方式类似于Swift语言中的 for - in循环,可以依次的自动去除迭代器中的值。

下方就是使用for - of 来循环遍历创建的迭代器。

从下方示例中我们不难看出直接输出的是迭代器返回对象的value值。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

4、在类中添加迭代器

我们可以在自己的类中添加相关方法,使我们自己的类支持迭代器。下方就创建了一个 RangeIterator 类,该类的作用是可以定义一个范围,构造器可以接受两个值,一个是范围的起始位置另一个是范围的结束点。下方我们为该范围类添加了自定义迭代器,具体说明如下:

在该类中添加了一个名为 next 的箭头函数,在该函数中做的事情与之前我们自定义的next方法差不多,主要是用来获取下一个值然后返回。

然后又实现一个[Symbole.iterator]函数,用来获取迭代器对象。最后我们可看到定义的范围对象可以向迭代器那样使用for-of进行遍历。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

5、调用迭代器的场景

迭代器的使用场景还是蛮多的,解构赋值、扩展运算符、Generator函数、yield*, 下方会简单的列举出来。

(1)、对数组或者集合的解构赋值

在下方代码片段中首先创建了一个名为 mySet 的集合对象。然后通过循环给集合中添加了一些值。然后通过 解构赋值 的形式,取出了 mySet 中的第一个值和第二个值。此刻的结构赋值会调用集合的迭代器接口,取出第一个值和第二个值,分别赋值给 first 和 second。

第二个红框中在结构赋值是使用了扩展运算符,该操作符会使 others 接收 firstItem 剩下的值。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

(2)、扩展运算符 ...

接下来来看另一个扩展运算符的例子。

首先定义了一个字符串,然后通过扩展运算符将该字符串的每个字符拆分到一个数组中,输出结果如下所示。扩展运算符还可以使用到对象上,如第二个示例所示。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

(3)、在Generator函数的 yield * 中使用

稍后会详细的介绍 Generator 函数,一个Generator 函数返回的是一个迭代器,我们可以调用该迭代器的 next 方法来执行每一个 yield。在 Generator 函数中,可以使用 yield * 后边跟一个可便遍历的结构,这样我们就可以在外部统一使用 next 来访问这个可遍历的结构的每一个值,如下所示:

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

二、Generator函数及异步编程

理解完迭代器,接下来来看一下Generator函数。如果做过RN开发的话,如果使用过 redux - saga的话,应该对Generator函数不陌生。Generator函数是ES6提供的异步编程的解决方案,解析了我们先看一下Generator函数基本使用方式,再看一下如何使用Generator函数进行异步编程。

1、Generator函数的定义和使用

下方定义了一个 Generator函数,Generator函数的定义与普通函数的定义差不多,只不过是function关键字后边跟了一个*号。然后函数体内部使用了一个个 yield语句来表明每一步的操作。定义完Generator函数后,下方紧接着的是使用,首先调用该Generator函数获取了一个迭代器,每次执行这个迭代器的next方法都会一次的执行一个yield语句。输出结果和上面的迭代器没啥区别。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

2、next的参数

在调用Generator函数返回的迭代器时,是可以往next方法中传入参数的。next 方法可以带一个参数,该参数被当做上一个 yield 语句的返回值。下方就是给 next 传参的一个示例:

下方定义了一个Generator函数,用来输出自增的值,每次调用next都会获取一个自增的值。当调用 rg.next(true) 时,这个true就会被赋值给 reset, 因为这个reset被视为上个yield的返回值,上一个yield执行后,会将index设置为 -1。那么rg.next(true)对应的 yield执行是,index是从 -1 开始自增的,自增后为0,所以 rg.next(true) 对应的 yield 的值为0。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

下方是另一个示例:

下方定义了一个名为testNextValue的Generator函数,该函数本身接收了一个参数。在调用该Generator函数时,传入了一个参数,这个参数不是Next的参数,是Generator函数本身的参数。

Generator函数在调用时,函数体并不会马上执行,在调用next函数时才会执行函数中yield语句体。

第一次调用Next,给Next传入了一个值 5,也就是说明 x = 5。

第一次执行next会调用第一个 yield 语句体,test1.next(2) = x + 1 = 5 + 1 = 6, 所以第一次调用next的结果值为

6。第二次调用 Next,传入的Next参数为3。

这个3 被作为上一个 yield 语句体的返回值,yield(x + 1) 的返回值为 3。那么 y 的值就为 2 * 3 = 6。yield中的值为 y / 3 = 2,所以第二次执行next获取的值为 2。第三次调用Next传入的参数为 4,这个 4 被作为上个yield语句体返回的参数,所以z = 4, 上分析过了 x = 5, y = 6, 所以 x + y + z = 15, 第三次执行next为 15。再次调用Next,因为语句体执行完了,所以获取到的是undefined。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

三、使用Generator函数进行异步编程

接下来实现一个简单的示例,使用Generator函数结合Promise回调模拟一下异步编程。

首先定义了一个 getPromise函数,该函数接收两个参数,一个参数表示网络请求的参数,另一个参数表示请求时间。该函数返回一个 Promise对象,在Promise对象中我们使用了setTimeout来模拟请求的延迟,根据传入的timeout来决定延迟时间,延迟时间到达后会执行 resolve方法,将相关值回调出来。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

然后定义了一个Generator函数,在该函数中通过yield来调用每个函数,下方的Generator函数比较简单,在此就不做过多赘述了。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

然后我们通过for -of 一次执行Generator函数的next方法,进而来执行每个getPromise方法。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

下方是具体的执行结果,从执行结果中不难看出,每次获取的yield值是一个Promise对象,我们可在该Promise对象的then方法中获取到相关的结果值。从输出顺序中可以看出,会先输出时间小的那个结果。

ES6中的迭代器、Generator函数及Generator函数的异步操作方法

总结

以上所述是小编给大家介绍的ES6中的迭代器、Generator函数及Generator函数的异步操作,希望对大家有所帮助,如果大家有任何疑问欢迎给我留言,小编会及时回复大家的!

Javascript 相关文章推荐
让FireFox支持innerText的实现代码
Dec 01 Javascript
两种常用的javascript数组去重方法思路及代码
Mar 26 Javascript
javaScript 计算两个日期的天数相差(示例代码)
Dec 27 Javascript
JS实现网页背景颜色与select框中颜色同时变化的方法
Feb 27 Javascript
Sea.JS知识总结
May 05 Javascript
ES6新特征数字、数组、字符串
Oct 01 Javascript
微信小程序 商城开发(ecshop )简单实例
Apr 07 Javascript
详解Vue2.0之去掉组件click事件的native修饰
Apr 20 Javascript
JavaScript之面向对象_动力节点Java学院整理
Jun 29 Javascript
VUE v-for循环中每个item节点动态绑定不同函数的实例
Sep 26 Javascript
Egg.js 中 AJax 上传文件获取参数的方法
Oct 10 Javascript
从零开始在vue-cli4配置自适应vw布局的实现
Jun 08 Javascript
浅谈vue.use()方法从源码到使用
May 12 #Javascript
Vue安装浏览器开发工具的步骤详解
May 12 #Javascript
微信小程序缓存过期时间的使用详情
May 12 #Javascript
从0到1搭建element后台框架优化篇(打包优化)
May 12 #Javascript
Vue项目服务器部署之子目录部署方法
May 12 #Javascript
vue配置接口域名方法总结
May 12 #Javascript
详解babel升级到7.X采坑总结
May 12 #Javascript
You might like
php进行支付宝开发中return_url和notify_url的区别分析
2014/12/22 PHP
PHP入门教程之表单与验证实例详解
2016/09/11 PHP
PHP输出图像imagegif、imagejpeg与imagepng函数用法分析
2016/11/14 PHP
PHP implode()函数用法讲解
2019/03/08 PHP
Laravel 6 将新增为指定队列任务设置中间件的功能
2019/08/06 PHP
js之事件冒泡和事件捕获详细介绍
2013/10/28 Javascript
JS动态改变浏览器标题的方法
2016/04/06 Javascript
thinkjs之页面跳转同步异步操作
2017/02/05 Javascript
浅谈JavaScript正则表达式-非捕获性分组
2017/03/08 Javascript
JS脚本加载后执行相应回调函数的操作方法
2018/02/28 Javascript
webpack打包react项目的实现方法
2018/06/21 Javascript
vue-cli 使用vue-bus来全局控制的实例讲解
2018/09/15 Javascript
ajaxfileupload.js实现上传文件功能
2019/04/19 Javascript
微信小程序实现可拖动悬浮图标(包括按钮角标的实现)
2020/12/29 Javascript
[56:18]VGJ.S vs Secret 2018国际邀请赛小组赛BO2 第二场 8.16
2018/08/17 DOTA
[48:18]DOTA2-DPC中国联赛 正赛 RNG vs Dynasty BO3 第二场 1月29日
2021/03/11 DOTA
django创建自定义模板处理器的实例详解
2017/08/14 Python
python 定时器,实现每天凌晨3点执行的方法
2019/02/20 Python
Django打印出在数据库中执行的语句问题
2019/07/25 Python
python中matplotlib条件背景颜色的实现
2019/09/02 Python
Python猴子补丁知识点总结
2020/01/05 Python
python 弧度与角度互转实例
2020/04/15 Python
Python中无限循环需要什么条件
2020/05/27 Python
Python 添加文件注释和函数注释操作
2020/08/09 Python
Python3读写ini配置文件的示例
2020/11/06 Python
英国最大的香水商店:The Fragrance Shop
2018/07/06 全球购物
教师网络培训感言
2014/03/09 职场文书
2014年语文教研组工作总结
2014/12/06 职场文书
先进集体事迹材料范文
2014/12/25 职场文书
2015年财务科工作总结范文
2015/05/13 职场文书
2015年学校办公室主任工作总结
2015/07/20 职场文书
优秀乡村医生事迹材料(2016精选版)
2016/02/29 职场文书
哪类餐饮行业,最适合在高校创业?
2019/08/19 职场文书
为什么代码规范要求SQL语句不要过多的join
2021/06/23 MySQL
企业版Windows 11有哪些新功能? Win11适用于企业的功能介绍
2021/11/21 数码科技
MySQL数据库中的锁、解锁以及删除事务
2022/05/06 MySQL