Generator 函数

每当函数被调用时,JavaScript 引擎就会在函数顶部启动,并运行每行代码,直到到达底部。无法中途停止运行代码,并稍后重新开始。一直都是这种“运行到结束”的工作方式.

如果我们希望能够中途暂停运行函数,则需要使用 ES6 中新提供的一种函数,叫做 generator(生成器)函数!我们来看一个示例:

function* getEmployee() {
    console.log('the function has started');

    const names = ['Amanda', 'Diego', 'Farrin', 'James'];

    for (const name of names) {
        yield name;
    }

    console.log('the function has ended');
}

注意到 function 关键字后面的星号(即 *)了吗?星号表示该函数实际上是生成器!

关键字 yield 是 ES6 中新出现的关键字。只能用在生成器函数中。yield 会导致生成器暂停下来。函数体内部使用yield表达式,定义不同的内部状态(yield在英语里的意思就是“产出”)。

现在看看当我们尝试运行该函数时,会发生什么:

getEmployee();

// this is the response I get in Chrome:
getEmployee {[[GeneratorStatus]]: "suspended", [[GeneratorReceiver]]: Window}

结果是控制台中没有输出我们所期待的,怎么回事呢?

事实上,生成器被调用时,它不会运行函数中的任何代码,而是创建和返回迭代器。该迭代器可以用来运行实际生成器的内部代码。

Generator 函数的调用方法与普通函数一样,也是在函数名后面加上一对圆括号。不同的是,调用 Generator 函数后,该函数并不执行,返回的也不是函数运行结果,而是一个指向内部状态的指针对象,也就是上一章介绍的遍历器对象(Iterator Object)。

下一步,必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。

const generatorIterator = getEmployee();
 generatorIterator.next();
 //{value: "Amanda", done: false}
 
 generatorIterator.next();
 //{value: "Diego", done: false}
 
 generatorIterator.next();
 //{value: "Farrin", done: false}

 generatorIterator.next();
 //{value: "James", done: false}
 
 generatorIterator.next();
 //{value: "undefined", done: true}

我们可以使用关键字 yield 从生成器中获取数据。我们还可以将数据发送回生成器中。方式是使用 .next() 方法:

yield表达式本身没有返回值,或者说总是返回undefinednext方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。

 function* createSundae() {
    const toppings = [];

    toppings.push(yield);
    toppings.push(yield);
    toppings.push(yield);

    return toppings;
}
var it = createSundae();
it.next('hot fudge');
it.next('sprinkles');
it.next('whipped cream');
it.next().value();
// ['sprinkles','whipped cream',undefined]

使用数据调用 it.next('hot fudge');会将该数据发送到生成器函数中上次离开的地方。它会将 yield 关键字替换为你提供的数据。


escaple_plan
287 声望10 粉丝