JavaScript中的Generator函数
前言 🔗
在学习Async的时候可以先学习generator函数
generator是ES6提出的一种特性,基于这个特性,可以去分段的执行函数
也就是函数执行到某一行,跳出之后可以重新进入到上次的状态
Generator 🔗
Generator 意思为生成器
在js中,Generator是一种特殊的函数
Generator的关键字为在function和括号之间加一个*号
以及在函数体内使用yield关键字
function* fn() {
yield 1;
}简单点讲,生成器函数可以在yield的位置暂停执行,返回yield紧接着的表达式的值
运行一个Generator函数会返回一个生成器对象
通过调用next方法可以得到迭代器(Iterator)对象
可以通过next放方法获取下一个yield的值
function* fn() {
yield 1;
yield 2;
return 3;
}
const iterator = fn();
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: true }通过执行函数得到一个生成器对象,这时候函数是还没有执行的
需要通过不断地调用next函数来进行执行
可以看出,next返回的对象value属性的值对应yield后面的表达式的值
而done则是表明此时迭代是否结束的标志
这也就是迭代器的结构
如果我们不写return 3,而是直接返回的话,就可以使用循环来判断是否到达了迭代的末尾
function* fn() {
yield 1;
yield 2;
return;
}
const iterator = fn();
let item = iterator.next();
while(!item.done){
console.log(item.value); // 以此输出 1 2
item = iterator.next();
}当然,我们可以给每次调用的next传入参数,传入的参数作为yield的返回值
function* fn() {
const r = yield 1;
yield r;
return;
}
const iter = fn();
console.log(iter.next('我是传入的参数')); // { value: 1, done: false }
console.log(iter.next()); // { value: '我是传入的参数', done: false }
console.log(iter.next()); // { value: undefined, done: true }generator有什么好处呢
比如我们现在需要一个函数来生成唯一id的话
不使用generator可以这么写
let id = 0;
function getId() {
id++;
return id;
}
getId(); // 1
getId(); // 2
getId(); // 3由于函数无法记忆状态,所以只能将变量放在全局
这样会造成变量污染
还可以使用闭包来改进上面的函数
const getId = (function getId() {
let id = 0;
return function (){
id++;
return id;
}
})();
getId(); // 1
getId(); // 2
getId(); // 3如果使用generator,看起来会更加直观
function* getId() {
let id = 1;
let ct = yield id;
while(!ct) {
id++;
ct = yield id;
}
}
const gen = getId();
gen.next(); // 1
gen.next(); // 2
gen.next(); // 3
gen.next(true); // undefined 不想自增了,结束掉在MDN上可以看到,除了next方法之外
generator对象还有return和throw
return函数用于直接结束生成器,即把生成器置于完成状态
function* fn() {
yield 1;
yield 2;
return;
}
const gen = fn();
gen.next(); // { value: 1, done: false }
gen.return(); // { value: undefined, done: true }
gen.next(); // { value: undefined, done: true } 生成器结束了,next也就是返回最后的结果,这个最后的结果可能是执行到结束的结果,也可能是调用return的结果
gen.return(3); // { value: 3, done: true } 可以重复地调用return,根据参数返回对应的值throw用于向生成器抛出一个异常
function* fn() {
try {
yield 1;
yield 2;
} catch (e) {
console.log(e); // 输出给你一个大嘴巴子
}
}
const gen = fn();
gen.next(); // 1;
gen.throw(new Error('给你一个大嘴巴子'));throw返回的也是一个迭代器对象
如果此时生成器还能继续到达下一个yield的话
那么返回的就是下一个yield
如果不能到达,那么返回的迭代器对象里面的done为true
function* fn() {
try {
yield 1;
yield 2;
} catch (e) {
console.log(e); // 输出给你一个大嘴巴子
}
yield 3;
}
const gen = fn();
gen.next(); // 1;
gen.throw(new Error('给你一个大嘴巴子')); // 报错,返回了 { value: 3, done: false }需要注意,ie不支持generator这个特性
后记 🔗
惆怅,许愿一个实习…
