书籍参考:《ECMAScript 6入门》 作者:阮一峰
文档参考:MDN
概念
ES6提供了一种Generator函数,用来解决异步编程的方案,可以通过yield
命令来控制函数内部执行与暂停,它与传统的函数声明非常相似,但是有一点是,是函数声明关键字后面跟了一个星号*
,而且在函数内部通过yield
命令来控制函数的行为,在外面使用next
方法来执行函数内部的代码,直至下一个yield
命令。
先看看普通函数是怎么声明
function g(){
let value = '这是普通函数';
console.log(value);
}
g(); // '这是普通函数'
下面是一个Generator函数的声明使用
function* g(){
yield '这是Generator函数';
}
let gen = g();
gen.next(); // {value: "这是Generator函数", done: false}
gen.next(); //{value: undefined, done: true}
上面的代码简单的声明了一个Generator函数g,我们调用g函数的时候,g函数不会立即执行,它会返回一个遍历器,这个遍历器由next()
方法执行,直至yield
命令暂停,如果后面没有了yield
命令,则返回一个对象{value: undefined, done: true}
。其实Generator函数返回的遍历器很像Iterator遍历器。
next()参数
Generator函数返回的遍历器的next()
方法可以带参数,如果没有带参数表示上一条yield
命令后面跟的表达式返回的值为undefined
,如果带了参数,表示这个参数为上一条yield
命令后面表达式返回的值。
function* g(){
let x = yield 10;
let y = x + 10;
console.log(y);
}
let gen = g();
gen.next(); // {value: 10, done: false}
gen.next(); // Nan 同时返回 {value: undefined, done: true}
gen.next(); // {value: 10, done: false}
gen.next(20); // 30 同时返回 {value: undefined, done: true}
我们通过给next()
传入参数,可以改变函数默认的行为,这个也就给我们动态控制函数执行带来了很大的作为。
return命令
在Generator函数内部,可以出现一个return命令,如果执行return命令后,代表这个Generator函数已经结束,不会继续执行后面的代码了。
function* g(){
yield 1;
return 2;
yield 2;
}
let gen = g();
gen.next(); // {value: 1, done: false}
gen.next(); // {value: 2, done: true} 注意这里done的值已经标注为true,说明Generator已经结束
gen.next(); // {value: undefined, done: true}
return()方法
Generator函数返回的遍历器有一个return()
方法,执行这个方法后,Generator函数结束执行,不再执行后续代码了。
function* g(){
yield 1;
yield 2;
yield 3;
}
let gen = g();
gen.next(); // {value: 1, done: false}
gen.return(5); // {value: 5, done: true}
gen.next(); // {value: undefined, done: true}
throw()方法
Generator函数返回的遍历器有一个throw()
方法,它用于触发错误,这个错误我们可以在Generator函数内部捕获,也可以在外部捕获。
function* g(){
yield 1;
try {
yield;
} catch (e) {
console.log(e);
}
yield 2;
}
let gen = g();
gen.next(); // {value: 1, done: false}
gen.throw('内部捕获错误'); // Uncaught 内部捕获错误
yield*语法
Generator函数内部可以通过yield
语法调用另外一个Generator函数,语义上很好理解yield*
语法,yield
后面跟着一个星号而function
后面跟一个星号都代表它返回一个遍历器对象。
function* g1(){
yield 1;
yield 2;
}
function* g2(){
yield 3;
yield g1();
}
上面的代码是无法实现调用Generator函数,next()方法直接把g1返回的遍历器对象指针返回到对象中{value: g1, done: false},而下面是可以正常执行我们预计的结果。
function* g1(){
yield 1;
yield 2;
}
function* g2(){
yield 3;
yield* g1();
}
上面的代码等同于:
function* g2(){
yield 3;
yield 1;
yield 2;
}
应用场景
Generator函数非常适合流程控制,比如我们在加载DOM的时候,下面的代码是流程控制加载一个list列表,我们每次执行next()
方法,就会加载一个DOM结构。第一执行加载一个list的div,第二次执行会在这个div中加载ul,第三次执行会在ul中加载一个li,最后完成加载过程。
function* loadUiList(){
yield loadUiDiv();
yield loadUiUl();
yield loadUiLi();
}
文完!
《ES6-Generator函数》留言数:0