Generator
Generator
函数是 ES6 提供的一种异步编程解决方案,它返回的就是一个Iterator
结构,同时它是async/await
的底层。
基本语法
function* gen() {
yield 1;
yield 2;
yield 3;
return 4;
}
const genIt = gen();
genIt.next(); // {value: 1, done: false}
genIt.next(); // {value: 2, done: false}
genIt.next(); // {value: 3, done: false}
genIt.next(); // {value: 4, done: true}
genIt.next(); // {value: undefined, done: true}
上面的代码定义了一个 Generator
函数 gen
,它与正常的函数的区别仅仅是在 function
后面紧跟了一个 *
(不是规范一定要如此,但是推荐。也可以 function *),js 通过这个标识识别这是一个 Generator
函数,所以它内部可以实现其他函数无法实现的功能。
如 yield
关键字,函数执行的时候,遇到这个关键字就会停止,直到手动的调用 next()
。
通过上面的例子:
- 调用
Generator
函数时,函数并不会立即执行,而是一个指向内部状态的指针对象; - 第一次调用
next
方法后,开始执行函数,遇到第一个yield
后,停止执行,并将yield
后面的计算式计算出结果并返回; - 再一次调用
next
后,从上一次执行停止的地方开始执行,直到遇到下一个yield
; - 直到执行完成,或者遇到
return
后停止; - 它的执行逻辑与
遍历器对象(Iterator Object)
相同。
next 方法
Generator
函数通过yield
关键字来暂停内部代码运行位置;通过next()
方法,将指向内部状态的指针继续运行。当调用next()
后,将指针所在位置的yield
后面的数据返回。
function* demo() {
let i = 0;
while (i >= 0) {
yield i;
i++;
}
}
const it = demo();
console.log(it.next()); // { value: 0, done: false }
console.log(it.next()); // { value: 1, done: false }
console.log(it.next()); // { value: 2, done: false }
yield
作为表达式时
yield
还可以当作表达式参与运算, 此时yield
整块内容需要加上括号;与之对应的,此时调用next(param)
方法需要添加参数,而参数param
会在执行时,代替(yield xxx)
在代码中执行。
- next 入参示例:
如果
yield
参与到计算中,需要加括号。
function* demo() {
var a = 1;
var b = 2;
var num = 2 * (yield a + b);
}
var demoIt = demo()
demoIt.next(4); // 此时,var num = 2 * (yield a + b) === var num = 2 * 4
- 复杂示例。
function* gen(i) {
var a = yield i + 1;
var b = 2 * (yield (a + 1));
var c = yield (b / 2);
return (a + b + c);
}
var genIt = gen(2);; // 此时代码不执行,仅仅拿到指向内部状态的指针,并让 i = 2;
genIt.next(); // 返回 {value: 3, done: false}; 其中 value = i + 1;
gen.next(4);; // 返回 {value: 5, done: false}; 其中 a = (yield i + 1) = 4;
gen.next(2);; // 返回 {value: 2, done: false}; 其中 b = 2 * (yield (a + 1)) = 2 * 2 = 4
gen.next(4);; // 其中 c = yield (b / 2) = 4; 返回 {value: 12, done: true}; 所以 value= 4 + 4 + 5
与 Iterator
的关系
Generator 函数执行后,返回一个遍历器对象。该对象本身也具有Symbol.iterator属性,执行后返回自身。
function* gen(){
// some code
}
var g = gen();
g[Symbol.iterator]() === g
与 async/await
的关系
async函数就是将 Generator 函数的星号(*)替换成async,将yield替换成await,仅此而已。
function* gen() {
yield 1;
yield 2;
}
async function asyncDemo() {
await xxx;
await xxx;
}
优点
async/await
具有更好的语义化;async/await
具有内置的执行器,不需要手动执行;async/await
返回值是Promise
,可以用.then
操作。