生成器是一种特殊类型的函数。
我们正常从头到尾运行标准函数时候,最多只能生成一个值(return出一个值),但是生成器函数会在几次运行请求中暂停,因此每次运行都可能会生成一个值。
1、生成器函数
生成器函数能生成一组值得序列,但是每个值的生成是基于每次请求的,并且不是标准函数那样立即生成。必须显示的项生成器函数请求一个新的值,随后生成器要么响应出一个新值,要么告诉我们之后都不会再生成新值。
function* fn() { yield "1"; yield "2"; } for(let val of fn()) { console.log(val,'val') }
如上,我们可以循环输出生成器函数的值
原因:可以简单理解为 调用生成器并不会执行生成器函数,相反,它会创建一个叫做迭代器的对象
1.1通过迭代器对象控制生成器
function* generatorFn() { yield "xiaoming"; yield "xiaohong"; yield "xiaole"; }const myInterator = generatorFn(); // 调用生成器得到一个迭代器// 1、调用迭代器的next方法,向生成器请求一个新值 2、result1 为一个对象,其中包含着一个返回值和一个指示器百世之后是否还有新值生成const result1 = myInterator.next(); console.log(result1,'result1');
// {"value": "xiaoming","done": false} result1
迭代器用于控制生成器的执行
调用迭代器对象的next方法后,生成器就开始执行代码,当执行到yeild的之后,会生成一个中间值,然后返回一个新对象(里面有value和done)
每当生成一个当前的值后,生成器会非阻塞的挂起执行,等待下一次的请求的到达
随后再次调用next
const result1 = myInterator.next();
此时会将生成器从挂起状态唤醒,继续从上次离开的位置继续执行代码,直到遇到另一个中间值yeild,然后返回一个新的对象
最后一次调用next时,生成的新对象的value为undefined,done为true
使用while循环来迭代生成器生成的值序列
原理:通过调用生成器的得到的迭代器,会暴露出一个next方法,next能让我们向生成器请求一个新值。next方法返回一个有value和done的对象,done为true时候表示之后不会再生成新值
function* generatorFn() { yield "xiaoming"; yield "xiaohong"; yield "xiaole"; } const myInterator = generatorFn(); let item; while(!(item = myInterator.next()).done) { console.log(item,'item') }
// {value: 'xiaohong', done: false} 'item'
// {value: 'xiaole', done: false} 'item'
yeild后也可以调用另一个生成器
function* generatorFn() { yield "xiaoming"; yield *generatorFn2(); yield "xiaole"; } function* generatorFn2() { yield '2-xiaoming'; yield '2-xiaohong'; yield '2-xiaole'; } const myInterator = generatorFn(); let item; while(!(item = myInterator.next()).done) { console.log(item,'item') }
// 输出
{value: 'xiaoming', done: false} 'item'
{value: '2-xiaoming', done: false} 'item'
{value: '2-xiaohong', done: false} 'item'
{value: '2-xiaole', done: false} 'item'
{value: 'xiaole', done: false} 'item'
1.2与生成器交互
作为生成器函数参数发送值
function* generatorFn3(action) {
const yieldVal1 = yield ('1' + action);
console.log(yieldVal1,'yieldVal1');
const yieldVal2 = yield ('2' + yieldVal1 + action);
console.log(yieldVal2,'yieldVal2');
}
const myInterator3 = generatorFn3('向生成器函数传参');
const res3 = myInterator3.next();
console.log(res3,'res3');
const res4 = myInterator3.next('next函数内传参');
console.log(res4,'res4');
const res5 = myInterator3.next();
console.log(res5,'res5');
使用next方法向生成器发送值
next调用的传参是上一个yield表达式的返回值
抛出异常
每个迭代器除了又next方法还有throw方法
function* generatorFn4() { try { yield "xiaoxiao"; console.log('fail'); // 此处的错误将不会发生 } catch(e) { console.log(e,"抛出catch异常") } } const res6 = generatorFn4(); res6.throw("异常抛出");
1.4生成器内部分析
工作过程:挂起开始---》执行---》挂起让渡---》完成
挂起开始:创建一个生成器后,任何代码都没有执行
执行:执行要么是刚开始,要么是从上次挂起的地方继续执行。时机:调用next并且done为false
挂起让渡:当生成器在执行过程中遇到一个yeild表达式时候,会创建一个包含返回值的新对象,随后再挂起执行;生成器在这个状态暂停并等待继续执行
完成:生成器执行期间,如果代码执行到return语句或者全部代码执行完毕
生成器是如何跟随执行环境上下文的
待补充。。。。
2、Promise
用于简单的处理异步任务
在promise钱,我们通常使用回调函数来处理异步任务,这样会存在三个较为明显的问题:
1、当执行长时间任务时候,发生异常,会错误丢失
2、回调地狱
3、执行很多的同步任务
promise对象用于作为异步任务结果的占位符,它代表一个我们暂时还没获取到但是在未来有希望获取的值(所以 promise会存在三种状态 pending rejected fulfilled)
promise的执行顺序
拒绝promise(显式和隐式)
链式调用promise(在链式调用中如何捕获错误)
Promise.all
Promise.race
生成器与Promise结合