迭代器(Iterator)和生成器(Generator)

迭代器和可迭代协议

redux-saga是建立在ES6的生成器基础上的,要熟练的使用saga,必须理解生成器。
要理解生成器,必须先理解迭代器和可迭代协议。

迭代

类似于遍历

遍历:有多个数据组成的集合数据结构(map、set、array等其他类数组),需要从该结构中依次取出数据进行某种处理,有特定的数据结构。

迭代:按照某种逻辑,依次取出下一个数据进行处理。

迭代器 iterator

JS语言规定,如果一个对象具有next方法,并且next方法满足一定的约束,则该对象是一个迭代器(iterator)。

next方法的约束:该方法必须返回一个对象,该对象至少具有两个属性:

  • value:any类型,下一个数据的值,如果done属性为true,通常,会将value设置为undefined
  • done:bool类型,是否已经迭代完成

通过迭代器的next方法,可以依次取出数据,并可以根据返回的done属性,判定是否迭代结束。

var  iterator = {
    total:5,
    index:1,
    next(){
        var obj = {
            value:this.index > this.total ? undefined:this.index, 
            done: this.index > this.total 
        }
        this.index++
        return obj;
    }
}

在这里插入图片描述

迭代器创建函数 iterator creator

它是指一个函数,调用该函数后,返回一个迭代器,则该函数称之为迭代器创建函数,可以简称为迭代器函数。

function createIterator(){
    let total = 3,
    index = 1;
    return {
    next(){
        var obj = {
            value:index > total ? undefined:index, 
            done: index > total 
        }
        index++
        return obj;
    }
    }
}

//用户迭代数组的迭代器
        function createArrayIterator(arr) {
            var i = 0; //下标从0开始迭代
            return {
                next() {
                    return {
                        value: arr[i++],
                        done: i > arr.length
                    }
                }
            }
        }

        var iterator = createArrayIterator([3, 6, 7, 2, 1, 3]);

可迭代协议

ES6中出现了for-of循环,该循环就是用于迭代某个对象的,因此,for-of循环要求对象必须是可迭代的(对象必须满足可迭代协议)

可迭代协议是用于约束一个对象的,如果一个对象满足下面的规范,则该对象满足可迭代协议,也称之为该对象是可以被迭代的。

可迭代协议的约束如下:

  1. 对象必须有一个知名符号属性(Symbol.iterator)
  2. 该属性必须是一个无参的迭代器创建函数

for-of循环的原理

调用对象的[Symbol.iterator]方法,得到一个迭代器。不断调用next方法,只有返回的done为false,则将返回的value传递给变量,然后进入循环体执行一次。

手写实现for-of

const obj = {
    [Symbol.iterator]:function createIterator(){
        let total = 3,
        index = 1;
        return {
        next(){
            var obj = {
                value:index > total ? undefined:index, 
                done: index > total 
            }
            index++
            return obj;
        }
        }
    }
}

const iterator = obj[Symbol.iterator]();
let next = iterator.next()
while(!next.done){
    //done属性为false进入循环
    const item = next.value;
            console.log(item); //执行循环体
            next = iterator.next();
}
//同上功能类似
for (const item of obj) {
    console.log(item)   
}

生成器 generator

generator

生成器:由构造函数Generator创建的对象,该对象既是一个迭代器,同时,又是一个可迭代对象(满足可迭代协议的对象)

//伪代码

var generator = new Generator();
generator.next();//它具有next方法
var iterator = generator[Symbol.iterator];//它也是一个可迭代对象
for(const item of generator){
    //由于它是一个可迭代对象,因此也可以使用for of循环
}

注意:Generator构造函数,不提供给开发者使用,仅作为JS引擎内部使用

generator function

生成器函数(生成器创建函数):该函数用于创建一个生成器。

ES6新增了一个特殊的函数,叫做生成器函数,只要在函数名与function关键字之间加上一个*号,则该函数会自动返回一个生成器

生成器函数的特点:

  1. 调用生成器函数,会返回一个生成器,而不是执行函数体(因为,生成器函数的函数体执行,收到生成器控制)
  2. 每当调用了生成器的next方法,生成器的函数体会从上一次yield的位置(或开始位置)运行到下一个yield
    1. yield关键字只能在生成器内部使用,不可以在普通函数内部使用
    2. 它表示暂停,并返回一个当前迭代的数据
    3. 如果没有下一个yield,到了函数结束,则生成器的next方法得到的结果中的done为true
  3. yield关键字后面的表达式返回的数据,会作为当前迭代的数据
  4. 生成器函数的返回值,会作为迭代结束时的value
    1. 但是,如果在结束过后,仍然反复调用next,则value为undefined
  5. 生成器调用next的时候,可以传递参数,该参数会作为生成器函数体上一次yield表达式的值。
    1. 生成器第一次调用next函数时,传递参数没有任何意义
  6. 生成器带有一个throw方法,该方法与next的效果相同,唯一的区别在于:
    1. next方法传递的参数会被返回成一个正常值
    2. throw方法传递的参数是一个错误对象,会导致生成器函数内部发生一个错误。
  7. 生成器带有一个return方法,该方法会直接结束生成器函数
  8. 若需要在生成器内部调用其他生成器,注意:如果直接调用,得到的是一个生成器,如果加入*号调用,则进入其生成器内部执行。如果是yield* 函数()调用生成器函数,则该函数的返回结果,为该表达式的结果
//模仿异步获取数据
function asyncGetData(){
    return new Promise(resolve=>{
        setTimeout(() => {
            resolve("异步数据获取成功")
        }, 3000);
    })
}

//生成器函数
function* createGenerator(){
    console.log("开始");
    let res = yield asyncGetData();
    console.log("第一次:",res);
    res = yield asyncGetData();
    console.log("第二次:",res);
    res = yield 1;
    console.log("结束",res);
}

//参数是一个生成器函数
function run(func){
    const generator = func();
    next()
    function next(nextVal){
        const result = generator.next(nextVal);
        if(result.done){
            //迭代结束
            return;
        }
        //简单判断是不是promise,更细的判断可以用isPromise库
        if(typeof result.value.then === "function"){
            result.value.then(data=>next(data));
        }else{
            next(result.value);
        }
    }
}

run(createGenerator)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值