2021-02-08 ES6中的Generator函数的基本使用

2021-02-08 ES6中的Generator函数的基本使用

异步编程方法:

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise对象
  • ES6的Generator函数异步应用

异步的概念:
简单来说就是一个任务不是连续完成的,而是分为两段执行,先执行第一段,转而去执行其他任务,等做好了准备,在回过头来执行第二段

Generator函数是一个状态机,封装了多个内部状态,执行Generator函数会返回一个遍历器对象,可以依次遍历Generator函数内部的每一个状态

Generator函数是一个普通函数,但是有两个特征:
1、function关键字与函数名之间有个星号
2、函数体内部使用yield表达式,定义不同的内部状态

调用Generator函数,该函数不执行,返回的不是函数运行结果而是一个指向内部状态的指针对象,下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态

也就是说,每次调用next方法,内容指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式或return语句未知

换言之,Generator函数是分段执行的,yield表达式是暂停执行的标记,next方法可以恢复执行,next方法返回的是一个对象{value,done},其中value是yield表达式或return返回的值,done表示遍历是否结束,遇到return是true

yield表达式
Generator函数返回的是一个遍历器对象,只有调用next方法才会遍历下一个内部状态,提供了yield可以暂停执行的标志
遍历器对象的next方法运行逻辑如下:

1)遇到yield表达式,就暂停执行后面的操作吗,并将紧跟yield后面的那个表达式的值,作为返回的对象的value属性值
2)下一次调用next方法,再继续往下执行,直到遇到下一个yield表达式
3)如果没有遇到yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value的值
4)如果该函数没有return语句,则返回的对象的value属性值为undefined

yield表达式与return语句既有相似之处也有区别。
相似之处在于都能返回紧跟在语句后面的那个表达式的值。
区别在于每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行,而return语句不具备记忆的功能

注:yield表达式本身并没有返回值,或者说总是返回undefined

next方法的参数
yield表达式本身没有返回值,或者说总是返回undefined。next方法可以带一个参数,该参数就会被上一个yield表达式的返回值

这个功能有很重要的意义,Generator函数从暂停状态到回复状态,它的上下文状态(context)是不变的。通过next方法的参数,就有办法在Generator函数开始运行之后,继续向内部注入值,也就是说,可以在Generator函数运行的不同阶段,从外部向内部注入不同的值,从而调整函数的行为

function* foo(x) {
  var y = 2 * (yield (x + 1));
  var z = yield (y / 3);
  return (x + y + z);
}

var a = foo(5);
a.next() // Object{value:6, done:false}
a.next() // Object{value:NaN, done:false}
a.next() // Object{value:NaN, done:true}

var b = foo(5);
b.next() // { value:6, done:false }
b.next(12) // { value:8, done:false }
b.next(13) // { value:42, done:true }

注意:由于next方法的参数是表示上一个yield表达式的返回值,所以在第一次使用next方法时,传递参数无效的。V8引擎直接忽略第一次使用next方法时的参数,只有从第二次使用next方法开始,参数才是有效的

function* dataConsumer() {
  console.log('Started');
  console.log(`1. ${yield}`);
  console.log(`2. ${yield}`);
  return 'result';
}

let genObj = dataConsumer();
genObj.next();
// Started
genObj.next('a')
// 1. a
genObj.next('b')
// 2. b

如果想第一次就调用next,就能够输入值,可以在Generator函数外面在包一层

function wrapper(generatorFunction) {
  return function (...args) {
    let generatorObject = generatorFunction(...args);
    generatorObject.next();
    return generatorObject;
  };
}

const wrapped = wrapper(function* () {
  console.log(`First input: ${yield}`);
  return 'DONE';
});

wrapped().next('hello!')
// First input: hello!

实际上是调用第二次的next函数

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值