跳到主要内容

认识

一、认识


Generator 函数是 ES6 提供的一种异步编程解决方案,语法行为与传统函数完全不同。Generator 函数将 JavaScript 异步编程带入了一个全新的阶段。

二、语法

function* genFun() {
yield 1;
yield 2;
return 3;
}

const gen = genFun();
const result1 = gen.next();
console.log(result1); //{ value: 1, done: false }
const result2 = gen.next();
console.log(result2); // { value: 2, done: false }
const result3 = gen.next();
console.log(result3); // { value: 3, done: true }

2.1 *

* 紧跟在function关键字后面, 用于声明这是一个 Genearator 函数。

function* fun(){}

2.2 yield

由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态,所以其实提供了一种可以暂停执行的函数。yield表达式就是暂停标志。

2.3 next()

由于 Generator 函数返回的遍历器对象,只有调用next方法才会遍历下一个内部状态

参数: yield表达式本身没有返回值,或者说总是返回undefinednext方法可以带一个参数,该参数就会被当作上一个yield表达式的返回值。注意,由于next方法的参数表示上一个yield表达式的返回值,所以在第一次使用next方法时,传递参数是无效的。V8 引擎直接忽略第一次使用next方法时的参数,只有从第二次使用next方法开始,参数才是有效的。从语义上讲,第一个next方法用来启动遍历器对象,所以不用带有参数。

function* genFun() {
console.log(yield 1); // 哈哈
console.log(yield 2); // 嘻嘻
return 3;
}

const gen = genFun();

const result1 = gen.next(); // 第一个 next 用于启动遍历器对象, 传参无效
console.log(result1); //{ value: 1, done: false }
const result2 = gen.next("哈哈"); // 为第一个 yield 提供返回值
console.log(result2); // { value: 2, done: false }
const result3 = gen.next("嘻嘻"); // 为第二个 yield 提供返回值
console.log(result3); // { value: 3, done: true }

返回值

const gen = genFun();

const result = gen.next();

result = {
value: 表示当前的内部状态的值
done: 是一个布尔值,表示是否遍历结束
}

运行逻辑

  1. 遇到yield表达式,就暂停执行后面的操作,并将紧跟在yield后面的那个表达式的值,作为返回的对象的value属性值。

  2. 下一次调用next方法时,再继续往下执行,直到遇到下一个yield表达式。

  3. 如果没有再遇到新的yield表达式,就一直运行到函数结束,直到return语句为止,并将return语句后面的表达式的值,作为返回的对象的value属性值。

  4. 如果该函数没有return语句,则返回的对象的value属性值为undefined

三、返回值


Generator 函数并不执行,返回也不是函数的执行结果,而是一个指向内部状态的遍历器对象 Iterator Object

const gen = genFun();

gen = Object [Generator] {}

四、运行机制


4.1 Generator 函数

Genearator 函数不会执行, 只返回一个指向内部状态的遍历器 Iterator Object

4.2 Interator 遍历器

Genearator 函数返回了一个指向内部状态的遍历器 Iterator Object。我们接下来必须调用遍历器对象的next方法,使得指针移向下一个状态。也就是说,每次调用next方法,内部指针就从函数头部或上一次停下来的地方开始执行,直到遇到下一个yield表达式(或return语句)为止。

每次调用遍历器对象的next方法,就会返回一个有着valuedone两个属性的对象。value属性表示当前的内部状态的值,是yield表达式后面那个表达式的值;done属性是一个布尔值,表示是否遍历结束。

const gen = genFun();

const result = gen.next();

result = {
value: 表示当前的内部状态的值
done: 是一个布尔值,表示是否遍历结束
}

4.3 Genearator、Interator

换言之,Generator 函数是分段执行的,yield表达式是暂停执行的标记,而next方法可以恢复执行。

五、综合对比


5.1 yield vs return

yield表达式与return语句既有相似之处,也有区别。

yield: 可以返回紧跟在语句后面的那个表达式的值, 每次遇到yield,函数暂停执行,下一次再从该位置继续向后执行, 一个函数里面, 可以执行多次(或者说多个)yield表达式

return: 可以返回紧跟在语句后面的那个表达式的值, 而return语句不具备位置记忆的功能, 一个函数里面,只能执行一次(或者说一个)return语句

5.2 Genearator vs Function

普通函数: 执行函数内部代码, 返回函数执行结果

Generator函数: 不执行函数内部代码, 返回一个指向内部状态的指针对象 Iterator Object

5.3 Generator vs Function Constructor

  • Generatornew 使用,会报错 foo is not a constructor

参考资料


详解JS的四种异步解决方案:回调函数、Promise、Generator、async/await(干货满满)