ES6-Generator函数

书籍参考:《ECMAScript 6入门》 作者:阮一峰

文档参考:MDN

1.概念

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遍历器

2.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()传入参数,可以改变函数默认的行为,这个也就给我们动态控制函数执行带来了很大的作为。

3.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}

4.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}

5.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 内部捕获错误

6.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;
}

7.应用场景

Generator函数非常适合流程控制,比如我们在加载DOM的时候,下面的代码是流程控制加载一个list列表,我们每次执行next()方法,就会加载一个DOM结构。第一执行加载一个list的div,第二次执行会在这个div中加载ul,第三次执行会在ul中加载一个li,最后完成加载过程。

function* loadUiList(){
    yield loadUiDiv();
    yield loadUiUl();
    yield loadUiLi();
}

文完!

文档信息

发表评论

电子邮件地址不会被公开。 必填项已用*标注