概述
生成器函数在执行时能暂停,后面又能从暂停处继续执行。调用一个生成器函数并不会马上执行它里面的语句,而是返回一个这个生成器的 迭代器 ( iterator )对象。当这个迭代器的 next() 方法被首次(后续)调用时,其内的语句会执行到第一个(后续)出现yield的位置为止,yield 后紧跟迭代器要返回的值。或者如果用的是yield*(多了个星号),则表示将执行权移交给另一个生成器函数(当前生成器暂停执行)。
1.生成器函数执行时是可暂停的,之后又能从暂停处继续执行。(暂停标识:yield
)
2.调用生成器函数返回的是一个迭代器(而不是函数内return的值,return 是函数结束标识也是生成器函数最后一个返回值)
3.yield
(中译:产出)后面跟的是迭代器的返回值。yeild
表达式自身是没有返回值的,或者说是undefined
。(yield
相当于一个标识符,next()
执行后返回的对象的value
属性的值就是yield
后面表达式的生成的值)
4.生成器函数执行后返回的迭代器首次使用next()
方法,会执行到第一个yield
的位置,并放回该yield
后紧跟着的表达式的值。
5.假如生成器函数中没有yield
关键字,该函数就变成了一个暂缓执行函数,具体表现为执行生成器函数不会执行函数内的代码,只有调用生成的迭代器的next()
后,函数内的代码才会执行。
6.next()
返回一个对象,表示当前成员的信息,这个对象包含两个属性:value
和 done
,value
属性表示本次 yield
后面表达式的生成的值,done
属性为布尔类型,表示生成器后续是否还有 yield
语句,即生成器函数是否已经执行完毕并返回。
7.yield
关键字只能用在生成器函数中。function* f(){function foo(){yield 1;}}
这样会报错。
生成器函数外在特征:function与函数名间有一个*,对间隔没有要求,都可以编译通过。推荐写法:function* f(){}
|
生成器函数 |
function* g(x,y,z){
let k=x+y;
console.log('pass');
yield k;
yield z;
return k+z;
}
let it=g(...[1,2,4])
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
暂缓执行函数(没有yield的生成器函数) |
function *g(){
console.log('直接执行生成器函数我是不会被打印出来的');
}
let it=g();
//试下把下面一句的注释解开
//it.next();
不会打印!解开注释后才打印
next()传参 |
yield
表达式本身没有返回值,或者说总是返回undefined
。
function* g(x){
let a=yield x;
console.log(a);
}
let it=g(5);
console.log(it.next());
console.log(it.next());
next()
可以带一个参数,该参数就会被当作上一个yield
表达式的返回值。因此第一次使用next()
时,传递参数是无效的。
function* g(x){
let y=2+(yield x);
let z=x+(yield y+2)
return z;
}
let it=g(5);
console.log(it.next());//{value: 5, done: false}
console.log(it.next());//{value: NaN, done: false}
console.log(it.next());//{value: NaN, done: true}
let it2=g(5);
console.log(it2.next());//{value: 5, done: false}
console.log(it2.next(2));//{value: 6, done: false}
console.log(it2.next(2));//{value: 7, done: true}
生成器函数的嵌套 yield* f() |
yield*
后面的 Generator 函数(没有return语句时),等同于在 Generator 函数内部,部署一个for…of循环。
实际上,任何数据结构只要有 Iterator 接口,就可以被yield*
遍历。
yield*
会将主函数的执行权交给被代理函数,之后的next()
都是执行被代理函数里面的代码直至被代理函数执行完成,next()
才会回到主函数中继续执行。
function* g(i){
yield i+1;
yield i+2;
yield* g2(3);// 移交执行权
yield* g2(3+i);// 移交执行权
yield i+3
}
function* g2(k){
yield 1+k;
yield 2*k;
}
let it=g(5)
for (let i = 0; i < 8; i++) {
console.log(it.next());
}
|
部署Iterator接口 |
function* g(obj){
const keys= Object.keys(obj);
for (let i=0; i < keys.length; i++) {
let key=keys[i];
yield {key,value:obj[key]}
}
}
let myObj = { foo: 3, bar: 7 };
for (let {key, value} of g(myObj)) {
console.log(key, value);
}
当然如果只是单纯的遍历对象,使用Object.entries()更为简单
let myObj = { foo: 3, bar: 7 };
for (let [k,v] of Object.entries(myObj)) {
console.log(k,v);
}
自动执行Generator函数 CO模块 |
function* g(){
yield 1;
yield 2;
yield 3;
}
function autoRun(g){
let it=g();
let obj=it.next();
while(!obj.done){
obj=it.next();
}
}
autoRun(g)
CO模块
co 模块是著名程序员 TJ Holowaychuk 于 2013 年 6 月发布的一个小工具,用于 Generator 函数的自动执行。co 模块可以让你不用编写 Generator 函数的执行器。
var co = require('co');
co(gen);
异步任务封装 |
function* gen(){
var url = 'https://api.github.com/users/github';
var result = yield fetch(url);
console.log(result.bio);
}
var g = gen();
var result = g.next();
result.value.then(function(data){
return data.json();
}).then(function(data){
g.next(data);
});
Generator 函数封装了一个异步操作,该操作先读取一个远程接口,然后从 JSON 格式的数据解析信息。fetch返回的是一个 Promise 对象,因此要用then
方法调用下一个next
方法。为此可以通过Promise队列实现异步任务的同步执行。
参考文档:
Generator 函数的语法
最后
以上就是调皮蚂蚁为你收集整理的JS Generator function* 生成器函数的全部内容,希望文章能够帮你解决JS Generator function* 生成器函数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复