最近在写 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.
自定义完迭代器后, 我们就可以对上述代码进行测试了.
首先创建了一个数组, 然后将数组传给 makeIterator 函数. 而 makeIterator 函数会返回一个含有 next 方法的迭代器对象.
我们将这个迭代器对象命名为 iterator, 我们就可以通过 iterator 的 next 方法来依次获取数组中的值了.
我们通过 while 循环来不断的调用 iterator 中的 next 方法, 直到 next 方法返回的对象中的 done 值为 true 时, 表示遍历结束.
遍历结束后, 我们再次调用 next() 方法, 得到的是{ value: undefind, done: true } 的对象, 表示遍历结束, 获取的 value 值为 undefined.
2,ES6 中的迭代器
类似于 Swift 语言的特性, ES6 规范中我们可以直接通过一些对象获取该对象所对应的迭代器, 如下所示:
下方示例中使用的数组和上面使用的 list 是一个, 首先我们通过 list[Symbol.iterator]() 的方式获取了 list 对应的迭代器.(Symbol 也是一种数据类型, 该数据类型用来表示独一无二的对象)
该迭代器的使用方式和输出结果与上述我们自定义的迭代器的使用方式完全一致, 输出结果与之前的结果也是一致的.
3, 使用 for - of 遍历迭代器
上述方式创建的迭代器我们是使用的 while 循环来进行遍历的, 除了 while 循环, 我们还可以通过 for-of 进行遍历. 此处的 for - of 遍历方式类似于 Swift 语言中的 for - in 循环, 可以依次的自动去除迭代器中的值. 下方就是使用 for - of 来循环遍历创建的迭代器.
从下方示例中我们不难看出直接输出的是迭代器返回对象的 value 值.
4, 在类中添加迭代器
我们可以在自己的类中添加相关方法, 使我们自己的类支持迭代器. 下方就创建了一个 RangeIterator 类, 该类的作用是可以定义一个范围, 构造器可以接受两个值, 一个是范围的起始位置另一个是范围的结束点. 下方我们为该范围类添加了自定义迭代器, 具体说明如下:
在该类中添加了一个名为 next 的箭头函数, 在该函数中做的事情与之前我们自定义的 next 方法差不多, 主要是用来获取下一个值然后返回.
然后又实现一个 [Symbole.iterator] 函数, 用来获取迭代器对象.
最后我们可看到定义的范围对象可以向迭代器那样使用 for-of 进行遍历.
5, 调用迭代器的场景
迭代器的使用场景还是蛮多的, 解构赋值, 扩展运算符, Generator 函数, yield*, 下方会简单的列举出来.
(1), 对数组或者集合的解构赋值
在下方代码片段中首先创建了一个名为 mySet 的集合对象. 然后通过循环给集合中添加了一些值. 然后通过 解构赋值 的形式, 取出了 mySet 中的第一个值和第二个值. 此刻的结构赋值会调用集合的迭代器接口, 取出第一个值和第二个值, 分别赋值给 first 和 second.
第二个红框中在结构赋值是使用了扩展运算符, 该操作符会使 others 接收 firstItem 剩下的值.
(2), 扩展运算符 ...
接下来来看另一个扩展运算符的例子.
首先定义了一个字符串, 然后通过扩展运算符将该字符串的每个字符拆分到一个数组中, 输出结果如下所示.
扩展运算符还可以使用到对象上, 如第二个示例所示.
(3), 在 Generator 函数的 yield * 中使用
稍后会详细的介绍 Generator 函数, 一个 Generator 函数返回的是一个迭代器, 我们可以调用该迭代器的 next 方法来执行每一个 yield. 在 Generator 函数中, 可以使用 yield * 后边跟一个可便遍历的结构, 这样我们就可以在外部统一使用 next 来访问这个可遍历的结构的每一个值, 如下所示:
二, Generator 函数及异步编程
理解完迭代器, 接下来来看一下 Generator 函数. 如果做过 RN 开发的话, 如果使用过 redux - saga 的话, 应该对 Generator 函数不陌生. Generator 函数是 ES6 提供的异步编程的解决方案, 解析了我们先看一下 Generator 函数基本使用方式, 再看一下如何使用 Generator 函数进行异步编程.
1,Generator 函数的定义和使用
下方定义了一个 Generator 函数, Generator 函数的定义与普通函数的定义差不多, 只不过是 function 关键字后边跟了一个 * 号. 然后函数体内部使用了一个个 yield 语句来表明每一步的操作. 定义完 Generator 函数后, 下方紧接着的是使用, 首先调用该 Generator 函数获取了一个迭代器, 每次执行这个迭代器的 next 方法都会一次的执行一个 yield 语句. 输出结果和上面的迭代器没啥区别.
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.
下方是另一个示例:
下方定义了一个名为 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.
三, 使用 Generator 函数进行异步编程
接下来实现一个简单的示例, 使用 Generator 函数结合 Promise 回调模拟一下异步编程.
首先定义了一个 getPromise 函数, 该函数接收两个参数, 一个参数表示网络请求的参数, 另一个参数表示请求时间. 该函数返回一个 Promise 对象, 在 Promise 对象中我们使用了 setTimeout 来模拟请求的延迟, 根据传入的 timeout 来决定延迟时间, 延迟时间到达后会执行 resolve 方法, 将相关值回调出来.
然后定义了一个 Generator 函数, 在该函数中通过 yield 来调用每个函数, 下方的 Generator 函数比较简单, 在此就不做过多赘述了.
然后我们通过 for -of 一次执行 Generator 函数的 next 方法, 进而来执行每个 getPromise 方法.
下方是具体的执行结果, 从执行结果中不难看出, 每次获取的 yield 值是一个 Promise 对象, 我们可在该 Promise 对象的 then 方法中获取到相关的结果值. 从输出顺序中可以看出, 会先输出时间小的那个结果.
本篇博客就先到这儿吧, 下篇会聊一些 saga 的相关内容.
来源: https://www.cnblogs.com/ludashi/p/10666084.html