generator

generator必须配合一个关键字yield才能使用

generator将一个函数封装成了多个片段,一个yield是一个片段

在函数内部只要碰到yield关键字就会停止运行

只要在generator实例化对象后面调用next指针就会恢复执行

generator是如何向外进行产出的呢?——原理
  • 通过yield关键字进行产出
  1. 先生成一个generator函数

  2. generator函数一执行就会生成generator实例化对象(不用new

  3. generator实例化对象身上调用next()的方法就可以使yield不断产出内容

  • yield关键字默认返回值为undefined
  • yield关键字有两个功能:
    • 会给指针方法赋值——即yield产出的值会赋值给产出的结果(next());
    • 但是yield在代码里有默认值,在操作完后会返回undefined——即代码中a + b 为 undefined + undefined即结果为NAN
  • next() 调用超出 yield 就没有产出,done:true
<script>
    function *gen() {
    let a = yield 6;
    let b = yield 8;
    let c = yield a + b;
    yield console.log(c);
}

let g = gen();
console.log(g.next());
//Object { value: 6, done: false }
console.log(g.next());
//Object { value: 8, done: false }
console.log(g.next());
//Object { value: NaN, done: false }
console.log(g.next());
//undefined
console.log(g.next());                      
//Object { value: undefined, done: true }
</script>

在generator中yiled以及return都能进行产出

碰到yield done:false

碰到return done:true——即产出完毕; 即终止状态,一般很少使用return

<script>
    function *gen() {
    let a = yield 6;
    return 22;
    let b = yield 8;
}

let g = gen();
console.log(g.next());
//Object { value: 6, done: false }
console.log(g.next());
//Object { value: 22, done: true }
console.log(g.next());
//Object { value: undefined, done: true }
</script>

generator改变了程序执行的流程

本身代码是连续执行的,但是成为片段后,需要调用指针才能执行,不调用就不执行

generator的核心是在何时调用next()——何时进行产出

  • next()里的参数会做为上一次yield关键字表达式的返回值进行使用

  • 相当于yield产出后默认返回值undefined替换成了参数

<script>
    function *gen() {
    let a = yield 6;
    let b = yield 8;
    let c = yield a + b;
    return 123;
}

let g = gen();
console.log(g.next());
//Object { value: 6, done: false }
console.log(g.next(55));
//Object { value: 8, done: false }
console.log(g.next(66));
//Object { value: 121, done: false }
console.log(g.next());
//Object { value: 123, done: true }
</script>

yield后面是函数不影响,还是相当于一个值

<script>
    function *gen() {
    let a = yield 6;
    let b = yield function *() {
        let f = yield 56;
        let e = yield 99;
        let g = yield f + e;
    }
    let c = yield a + b;
    return 44444
}

let g = gen();
console.log(g.next());
//Object { value: 6, done: false }
console.log(g.next(55));
//Object { value: * b(), done: false }
console.log(g.next(66));
//Object { value: 121, done: false }
console.log(g.next());
//Object { value: 44444, done: true }
    </script>

如果在yield后面加*这个函数不可遍历——is not iterable

<script>
    function *gen() {
    let a = yield 6;
    let b = yield* function *() {
        let f = yield 56;
        let e = yield 99;
        let g = yield f + e;
    }
    let c = yield a + b;
    return 44444
}

let g = gen();
console.log(g.next());
console.log(g.next(55));
console.log(g.next(66));
console.log(g.next());
</script>

generator 函数生成一个 generator 实例化对象

generator一般指generator实例化对象,generator函数的目的是为了生成generator实例化对象

generator函数全称叫做generator生成函数

<script>
    function *gen() {
    let a = yield 6;
    function *foo() {
        let f = yield 56;
        let e = yield 99;
        let g = yield f + e;
    };
    //generator 函数生成一个 generator 实例化对象
   //yield 后面不带 * 就产出一个 generator 实例化对象 
    let b = yield foo();
    let c = yield a + b;
    return 44444
}

let g = gen();
console.log(g.next());
//Object { value: 6, done: false }

console.log(g.next(55));
//Object { value: Generator, done: false }

console.log(g.next(66));
//Object { value: 121, done: false }
console.log(g.next());
//Object { value: 44444, done: true }
</script>
递归产出(yield*)

yield* *遍历的对后面的generator指针进行自动的调用——就是进入到上面的generator函数里进行yield调用

 <script>
     function *gen() {
     let a = yield 6;
     //不是普通函数,是 generator 函数
     function *foo() {
         let f = yield 56;
         let e = yield 99;
         let g = yield f + e;
     };
     
     //yield后面带*后已经不叫产出了, 往函数里面进行作用
     let b = yield* foo();
     let c = yield a + b;
     return 44444
 }

let g = gen();
console.log(g.next());
//Object { value: 6, done: false }
console.log(g.next());
//Object { value: 56, done: false }
console.log(g.next(66));
//Object { value: 99, done: false }
console.log(g.next(55));
//Object { value: 121, done: false }
</script>
generator 跟 iterator其实是一个东西

generator 实际上就是 iterator 的语法糖

generator的遍历器接口就是该函数本身

g[Symbol.iterator]不在g身上,在原型身上

generator所有的遍历器接口都是一样的——g[Symbol.iterator]

for...of 自动调用 next(),并且根据产出值donefalse还是true确定是否继续遍历

<script>
    function *gen() {
    let a = yield 6;
    function *foo() {
        let f = yield 56;
        let e = yield 99;
        let g = yield f + e;
    };
    let b = yield* foo();
    let c = yield a + b;
    return 44444
}

var g = gen();
//g[Symbol.iterator]不在g身上,在原型身上
g[Symbol.iterator] === gen
console.log(g);

//for...of 自动调用 next()
for (let some of gen()) {
    console.log(some);
}
//66
//55
//99
//NaN
</script>
for...of的原理(为了更好的理解generator的遍历器接口就是该函数本身)
  1. 先查看是否具备遍历器接口,如果有则调用接口并返回遍历器对象,反之报错
  2. 调用遍历器对象中的next方法,将该方法返回的对象中的value赋值给目标变量,根据返回的对象的done属性来决定是否进行下次遍历
  3. for...of 只保留donefalsevalue
<script>
    let index = 0;
let o = {
    next: function() {
        return {
            value: index++,
            done: index > 5 && true
        }
    },

    [Symbol.iterator]: function() {
        return {
            next: this.next
        }
    }
}

for (let some of o) {
    console.log(some);
}
</script>
generator函数的this

generator指的就是generator函数,就是带*的函数

generator返回的就是iterator遍历器对象

仍然是点在谁身上指向谁

<script>
    let arrLike = {
        0: 66,
        1: 88,
        2: 33,
        3: 456,
        length: 4,
        
        //生成的generator对象自带next() 方法
        [Symbol.iterator]: function *() {
            for (let i = 0; i < this.length; i++) {
                yield this[i] * i;
            }
            return;
        }
    }

for (let some of arrLike) {
    console.log(some);
}
</script>

return()方法

return方法是手动触发generator停止产出

只要记住return停止方法后返回value:undefined, done:false,表示产出结束,后面的yield全部不执行

 <script>
     function* gen () {
     yield 33;
     yield 66;   //return yield 66;
     yield 99;
     return 520
 }

let g = gen();

// reture 方法将指针一下调到了最后
// 里面传参的话,返回值的value就是里面的参数
console.log(g.next());
//相当于在该位置上最前面补上一个 return
console.log(g.return());


</script>

throw()方法

异常处理

<script>
    function* gen () {
    yield 33;
    yield 66;   //return yield 66;
    yield 99;
    return 520
}

let g = gen();

console.log(g.next());
//触发了错误
//与return类似
console.log(g.throw("throw error"));
//Uncaught throw error     
</script>
throw()抛出的错误既可以在generator外部捕获也可以在generator内部捕获

外部捕获

<script>
    function* gen () {
    yield 33;
    yield 66;   //return yield 66;
    yield 99;
    return 520
}

let g = gen();

console.log(g.next());

//会用try{}catch(error){}不会终止后面的代码
try{
    console.log(g.throw("throw error"));
} catch (error) {
    console.log(error);
}

console.log("++++++++++");

</script>

内部捕获

<script>
    function* gen() {
    try {
        console.log("--------------");
        //--------------
        yield 33;
        yield 99;
        console.log("++++++++++++++++");
        //+++++++++++++++++
        return 520
    } catch (error) {
        console.log("内部捕获");
        //内部捕获
    }
}

let g = gen();
console.log(g.next());
//Object { value: 33, done: false }
console.log(g.throw());
//Object { value: undefined, done: true }
console.log(g.next());
//Object { value: undefined, done: true }
</script>
  • generator 创建之初是为了调控代码的执行结构
  • 异步操作,同步写法
  • 以前写异步总是回调,一层一层的
  • 以后回调函数都会消失
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值