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
表达式本身没有返回值,或者说总是返回undefined
。next
方法可以带一个参数,该参数就会被当作上一个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
关键字替换为你提供的数据。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。