Generator 生成器基础和 Async/Await 原理
如何创建一个 Generator 生成器函数
- 把创建函数的“function”后面加一个“*”即可
- 箭头函数是无法变为生成器函数的
- 控制台详细输出 Generator 生成器函数,会有一个 isGenerator 这个属性,属性值为 true,并且不直接是 Function 的实例,是 GeneratorFunction 的实例
- 对于 ES6 中快捷方式创建的函数,直接在函数名前加*,就可以创建生成器函数了。
每一个生成器函数,都是 GeneratorFunction 这个类的实例
fn.__proto__->GeneratorFunction.prototype->Function.prototype
多了一个私有属性[[IsGenerator]]:true
生成器函数执行
- 首先并不会立即把函数体中的代码执行
- 而是返回一个符合迭代器规范的迭代器对象itor 「按照原型链查找,先找到 GeneratorFunction.prototype,在它上面有
- next 执行的返回结果是一个对象 {done: ,value:}
- return 执行返回的结果也是一个对象{done:true,value:方法传入的值} 相当于在函数体中执行遇到了 return,结束整个函数的执行。不会报红,再次执行 next=>{done:true ,value:undefined}
- throw 方法 手动抛出异常「控制台报红」;生成器函数中的代码,都不会再执行了!!抛出异常后,下面的代码也不会执行了!!
继续向上查找,有 Symbol(Symbol.iterator)
继续向上查找 找到 Object」
- 当 itor.next()执行
- 把函数体中的代码开始执行
- 返回一个对象
- done:记录代码是否执行完毕
- value:记录本次处理的结果
Generator 生成器函数的作用:可以基于返回的 itor「迭代器对象」,基于其 next 方法,控制函数体中的代码,一步步执行!!!
在生成器函数体中有个关键词 yield
- 每一次执行 next,控制函数体中的代码开始执行「或者从上一次暂停的位置继续执行」,直到遇到 yield 则暂停!
done:false
value:yield 后面的值 - 当遇到函数体中的 return 或者已经执行到函数最末尾的位置了,
done:true
value:函数的返回值或者 undifined
=====================
传值处理
itor.next(N):每一次执行 next 方法,传递的值会作为上一个 yield 的返回值「所以第一次执行 next 方法,传递的值是没有用的,因为在它之前没有 yield」
const fn = function* fn(...params) {
let x = yield 100;
console.log(x);
let y = yield 200;
console.log(y);
};
let itor = fn(10, 20, 30);
console.log(itor.next("first:111"));
console.log(itor.next("second:222"));
console.log(itor.next("three:333"));
===============
生成器函数的嵌套
const sum = function* sum() {
yield 300;
yield 400;
};
const fn = function* fu() {
yield 100;
yield* sum();
yield 200;
};
let itor = fn();
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
console.log(itor.next());
================
//需求:串行请求,有3个请求「请求需要的时间分分别是1000/2000/3000」
const delay = (interval = 1000) => {
return new Promise(resolve => {
setTimeout(() => {
resolve(`@@${interval}`)
}, interval)
})
}
const handle = function* handle() {
let value = yield delay(1000);
console.log(`第一个请求成功-->`, value);
value = yield delay(2000)
console.log(`第二个请求成功-->`, value);
value = yield delay(3000)
console.log(`第三个请求成功-->`, value);
}
let itor = handle()
const AsyncFunction = function AsyncFunction(generator,...params) {
let itor = generator(...params)
const next = x => {
let { done, value } = itor.next(x)
if (done) return
if (!(value instanceof Promise)) value = Promise.resolve(value)
value.then(next)
}
next()
}
AsyncFunction(handle)
ES8 (ECMAScript 2017)中,提供了async/await语法:用来简化Promise的操作,是Promise和Generator的语法糖,上面实现的AsyncFunction函数和Generator函数的配合使用就是async/await的原理!!
低版本的Node中,无法使用async/await。
co.js这个库,在Node中使用,可以让Node环境下,出现类似于async/await的效果