js中的生成器函数Generator

1、入门

function* fn() {
    console.log(1);
    //暂停!
    yield;
    //调用next方法继续执行
    console.log(2);
}
var iter = fn();
iter.next(); //1
iter.next(); //2

生成器解析如下:
1、函数生成器特点是函数名前面有一个‘*’

2、通过调用函数生成一个控制器

3、调用控制器的next()方法开始执行函数

4、遇到yield函数将暂停

5、再次调用控制器的next() 继续执行函数

yield关键词并不会像return一样立即结束函数,只是暂停这个生成器函数,直到下一次调用next方法会继续从yield位置向下执行。

generator的特点
  • 每当执行完一条yield语句后函数就会自动停止执行, 直到再次调用next();

  • yield关键字只可在生成器内部使用,在其他地方使用会导致程序抛出错误

  • 可以通过函数表达式来创建生成器, 但是不能使用箭头函数

  • 可以在generator函数运行的不同阶段从外部内部注入不同的值,从而改变函数的行为

  • yield语句无返回值,总是返回undefined

  • next方法可以带一个参数,参数被当做上一条yield的返回值。

function* generator() {
 const list = [1, 2, 3];
 for (let i of list) {
 yield i;
 } }
let g = generator();
console.log(g.next()); // {value: 1, done: false}
console.log(g.next()); // {value: 2, done: false}
console.log(g.next()); // {value: 3, done: false}
console.log(g.next()); // {value: undefined, done: true}

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

var a = foo(5);
a.next() //{value: 6, done: false}
a.next() //{value: NaN, done: false}, 2* undefined / 3 = NaN
a.next() //{value: NaN, done: true}, 5 + NaN + undefined = NaN

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

2、消息传递

除了暂停和继续执行外,生成器同时支持传值。
在函数的内容可以使用yield的关键词向外返回一个值,在next方法调用的时候可以拿到这个值

2.1、Demo1
function* fn() {
    var a = yield 'hello';
    yield;
    console.log(a);
}
var iter = fn();
var res = iter.next();
console.log(res); 
iter.next(2);
iter.next(); //2

在这里插入图片描述

解析如下:
1、可以看到,yield后面有一个字符串‘hello’,在第一次调用next时,暂停在这里且返回给了iter.next(),即res = {done:false,value:‘hello’}

2、由于暂停的地方是一个赋值语句,需要一个变量给a,于是第二个next()方法中传了一个参数2替换了yield,最后打印a得到了2。

2.2、demo2
function *foo(x) {
  let y = 2 * (yield (x + 1))
  let z = yield (y / 3)
  return (x + y + z)
}
let it = foo(5)
console.log(it.next())   // => {value: 6, done: false}
console.log(it.next(12)) // => {value: 8, done: false}
console.log(it.next(13)) // => {value: 42, done: true}

分析如下:

  • 首先 Generator 函数调用和普通函数不同,它会返回一个迭代器
  • 当执行第一次 next 时,传参会被忽略,并且函数暂停在 yield (x + 1) 处,所以返回 5 + 1 = 6
  • 当执行第二次 next 时,传入的参数12就会被当作上一个yield表达式的返回值,如果你不传参,yield 永远返回 undefined。此时 let y = 2 * 12,所以第二个 yield 等于 2 * 12 / 3 = 8
  • 当执行第三次 next 时,传入的参数13就会被当作上一个yield表达式的返回值,所以 z = 13, x = 5, y = 24,相加等于 42

3、yield与next()的使用

function* foo(x) {
  console.log('first');
  var y = 2 * (yield (x + 1));
  console.log('second');
  var z = yield (y / 3);
  console.log('third');
  return (x + y + z);
}

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

var b = foo(5);
b.next() // first  { value:6, done:false }    
b.next(12) // second   { value:8, done:false }   
b.next(13) // third { value:42, done:true }   
  • 首次调用next()方法表示开始执行generator函数

  • 之后在执行时遇到yield表达式,就暂停执行yield表达式之后的操作,但是yield表达式要执行,并且将yield表达式之后的值作为返回对象的value值

    比如说上面的generator函数,
    第一次调用next(),yield表达式x+1会执行,但是2*(yield (x+1))并不会执行

  • 再次调用next(val)方法,继续向下执行,同时val参数可作为yield返回对象的value值,继续向下执行,如果没有传则默认为NaN。如此往复,直到执行完毕。

注意:yield返回的对象中done表示执行状态,是否执行完毕

4、生成器函数封装如下

const fetchData = (arg) => new Promise(resolve => {
	setTimeout(() => {
		resolve('test data ' + arg)
	}, 3000)
})

// generator 函数最终返回一个Promise对象
// generator 中遇到yield, 先执行其后操作,等执行完成后,执行完next()方法,才能继续向下执行
function* test() {
	console.log('0')
	let res = yield fetchData('1')
	console.log('1', res)
	res = yield fetchData(res)
	console.log('2', res)
	res = yield fetchData(res)
	console.log('3', res)
	res = yield fetchData(res)
	console.log('4', res)
}

// 自动执行器run 
const run = g => {       
	const next = val => {
		const res = g.next(val)
		if(res.done) return res.value
		res.value.then(next)
	}

	next()
}

run(test())

输出结果如下
在这里插入图片描述

参考地址:https://blog.csdn.net/qinshengnan520/article/details/108287199

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值