• (七) ES6 新特性 —— 生成器


    CSDN话题挑战赛第2期
    参赛话题:学习笔记

    目录

    生成器函数的声明与调用

    生成器里面的yield函数

    生成器函数参数

    生成器函数实例——异步编程


    生成器其实就是一个特殊的函数,其作用主要体现在异步编程。在此之前,我们实现异步编程采用的是纯回调函数(一层套一层 回调地狱)。

    首先我们来认识一下生成器函数:

    生成器函数的声明与调用

    生成器函数与普通函数有所不同,它需要在 函数名与function 之间添加个 * 号。如:

    1. function * gen(){
    2. console.log("Hello");
    3. }
    4. let iterator = gen();
    5. console.log(iterator);
    '
    运行

    1. console.log("Hello"); 这行的输出没有出现
    2. 返回的结果是一个迭代器对象

    所以让gen()里面的代码运行只需运行iterator.next()

    生成器里面的yield函数

    作用:切割符,把函数分为几段

    1. function * gen(){
    2. yield '一只没有耳朵';
    3. yield '一只没有尾部';
    4. yield '真奇怪';
    5. }
    '
    运行

    代码1-3是一段,3-5是一段,5-7是一段,7-9是一段。三个切割符产生四段代码。

    1. function* gen() {
    2. console.log(111);
    3. yield '一只没有耳朵';
    4. console.log(222);
    5. yield '一只没有尾部';
    6. console.log(333);
    7. yield '真奇怪';
    8. console.log(444);
    9. }
    10. let iterator = gen();
    11. iterator.next();
    12. iterator.next();
    13. iterator.next();
    14. iterator.next();
    '
    运行

    每调用一次next()就执行一段。

    我们可以将iterator.next()( ——>注意iterator.next()返回的是一个对象)的内容打印一下:

    第一次调用返回第一个yield里面的内容,第二次调用返回第二个yield里面的内容,第三次调用返回第三个yield里面的内容,第一次接着往下走就没有了。

    生成器函数参数

    传参:

    1. function* gen(arg) {
    2. yield 111;
    3. yield 222;
    4. yield 333;
    5. }
    6. //执行获取迭代器对象
    7. let iterator = gen('AAA');
    '
    运行

    我们试着打印以下arg:

    1. function* gen(arg) {
    2. console.log(arg);
    3. yield 111;
    4. yield 222;
    5. yield 333;
    6. }
    7. //执行获取迭代器对象
    8. let iterator = gen('AAA');
    '
    运行

    发现控制台并没有输出结果。

    我们接着调用一下iterator.next()

    1. function* gen(arg) {
    2. console.log(arg);
    3. yield 111;
    4. yield 222;
    5. yield 333;
    6. }
    7. //执行获取迭代器对象
    8. let iterator = gen('AAA');
    9. console.log(iterator.next());
    '
    运行

    正常输出AAA 说明参数的传递并没有问题。

    注意:next方法可以传入实参,传入的实参就是yield语句的返回结果。

    1. function* gen(arg) {
    2. console.log(arg);
    3. let one = yield 111;
    4. console.log(one);
    5. yield 222;
    6. yield 333;
    7. }
    8. //执行获取迭代器对象
    9. let iterator = gen('AAA');
    10. console.log(iterator.next());
    11. // //next方法可以传入实参
    12. console.log(iterator.next('BBB')); //第二次调用的next的参数
    13. // 将作为第一个yield语句的返回结果
    '
    运行

    继续往下:

    1. function* gen(arg) {
    2. console.log(arg);
    3. let one = yield 111;
    4. console.log(one);
    5. let two = yield 222;
    6. console.log(two);
    7. let three = yield 333;
    8. console.log(three);
    9. }
    10. //执行获取迭代器对象
    11. let iterator = gen('AAA');
    12. console.log(iterator.next());
    13. // //next方法可以传入实参
    14. console.log(iterator.next('BBB')); //第二次调用的next的参数,将作为第一个yield语句的返回结果
    15. console.log(iterator.next('CCC')); //第三次调用的next的参数,将作为第二个yield语句的返回结果
    16. console.log(iterator.next('DDD')); //第四次调用的next的参数,将作为第三个yield语句的返回结果
    '
    运行

    生成器函数实例——异步编程

    异步编程是一种事件驱动编程,请求调用函数或方法后无需立即等待反应,可以立即执行其他任务,之前的任务响应返回后可以通过状态,通知和回调来通知调用者。

    实例:文件操作 网络操作(ajax, request) 数据库操作

    简单介绍一下异步编程之后,我们来看一下这样的一个需求:

    1s 后控制台输出 111 2s后输出 222 3s后输出 333

    简单实现的话我们可以通过定时器采取一层一层嵌套的方式来执行:

    1. setTimeout(() => {
    2. console.log(111);
    3. setTimeout(() => {
    4. console.log(222);
    5. setTimeout(() => {
    6. console.log(333);
    7. }, 1000);
    8. }, 2000);
    9. }, 3000);
    '
    运行

    这样执行起来很简单,但是如果后面还有新的异步任务的话,还需要更多的去嵌套,代码缩进不断向前,阅读工作量巨大。

    很容易造成回调地狱的现象。

    所以新的异步解决方案就是我们可以通过生成器函数来完成:

    三个函数分别完成三个异步任务。

    1. function one() {
    2. setTimeout(() => {
    3. console.log(111);
    4. iterator.next();//让下一段yield语句执行。
    5. }, 1000);
    6. }
    7. function two() {
    8. setTimeout(() => {
    9. console.log(222);
    10. iterator.next();
    11. }, 2000);
    12. }
    13. function three() {
    14. setTimeout(() => {
    15. console.log(333);
    16. iterator.next();
    17. }, 3000);
    18. }
    19. // 把三个函数的调用放到了yield语句里面:
    20. function* gen() {
    21. yield one();
    22. yield two();
    23. yield three();
    24. }
    25. //调用生成器函数
    26. let iterator = gen();
    27. // 让生成器函数调用起来。
    28. iterator.next();
    '
    运行

    这样也可以实现我们的需求。

    再一个需求:模拟获取,顺序获取数据 ——>用户数据 订单数据 商品数据

    1. function getUsers(){
    2. setTimeout(()=>{
    3. let data = '用户数据';
    4. //调用 next 方法, 并且将数据传入
    5. iterator.next(data);//第二次调用next,将作为第一个yield语句的返回结果
    6. }, 1000);
    7. }
    8. function getOrders(){
    9. setTimeout(()=>{
    10. let data = '订单数据';//第三次调用next,将作为第二个yield语句的返回结果
    11. iterator.next(data);
    12. }, 1000)
    13. }
    14. function getGoods(){
    15. setTimeout(()=>{
    16. let data = '商品数据';
    17. iterator.next(data);
    18. }, 1000)
    19. }
    20. function * gen(){
    21. let users = yield getUsers();
    22. let orders = yield getOrders();
    23. let goods = yield getGoods();
    24. }
    25. //调用生成器函数
    26. let iterator = gen();
    27. iterator.next();
    '
    运行

    当我们调用订单数据时,我们可能会需要用户数据的内容,所以可以再用户数据的函数中通过 iterator.next(data) 传递相关的内容,它将作为第一个yield语句的返回结果。

  • 相关阅读:
    Java集合大总结——Set的简单使用
    CockroachDB-备份与恢复(5)BACKUP命令
    【linux命令讲解大全】056.updatedb命令:创建或更新slocate数据库文件
    怎么突破反爬虫机制
    AMAZINGIC晶焱科技推出低操作电压ESD保护元件
    Java实验报告(三)
    【其他】sd卡的照片在相机上能看到在电脑上却看不到
    Gismo compile note
    记录一次bug
    ElasticSearch之安装
  • 原文地址:https://blog.csdn.net/a45667/article/details/127116633