Generator 生成器基础和 Async/Await 原理

Generator 生成器基础和 Async/Await 原理

ES6 提供的 API/方式
在 JS 中,生成器 Generator 是一种新的数据结构 它允许你定义一个函数,该函数可以根据需要一次返回(产出)一个值 而不是立刻返回所最终值,,可以在你需要的获取值

如何创建一个 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」

/* 
params:生成器函数接收的实参值,它是生成器函数执行时传递的值
fn(10,20,30)
params:[10,20,30]
*/
const fn = function* fn(...params) {
  let x = yield 100;
  console.log(x); //'second:222'
  let y = yield 200;
  console.log(y); //'three:333'
};
let itor = fn(10, 20, 30);
console.log(itor.next("first:111")); //=>{value:100,done:false}
console.log(itor.next("second:222")); //=>{value:200,done:false}
console.log(itor.next("three:333")); //=>{value:undefined,done:true}

===============
生成器函数的嵌套

const sum = function* sum() {
  yield 300;
  yield 400;
};
const fn = function* fu() {
  yield 100;
  yield* sum();//  yield* 支持进入另外一个生成器函数中去一步步的执行
  yield 200;
};
let itor = fn();
console.log(itor.next());//{value:100,done:false}
console.log(itor.next());//{value:300,done:false}
console.log(itor.next());//{value:400,done:false}
console.log(itor.next());//{value:200,done:false}
console.log(itor.next());//{value:undefined,done:true}

================
//需求:串行请求,有3个请求「请求需要的时间分分别是1000/2000/3000」

/* const delay=(interval=1000)=>{
  return new Promise(resolve=>{
    setTimeout(()=>{
      resolve(`@@${interval}`)
    },interval)
  })
} */
/* delay(3000).then(value=>{
  console.log(value)//=>@@3000
}) */

const delay = (interval = 1000) => {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(`@@${interval}`)
    }, interval)
  })
}
//方式1 用promise来写
/* delay(1000)
.then(value=>{
  console.log(`第一个请求成功-->`, value);
  return delay(2000)
})
.then(value=>{
  console.log(`第二个请求成功-->`, value);
  return delay(3000)
})
.catch(reason=>{
  console.log(`任何请求失败都走这里-->`, reason);
  
})
 */


//方式2 用async/await来写
/* (async ()=>{
  try {
    let value=await delay(1000);
    console.log(`第一个请求成功-->`, value);

    value=await delay(2000)
    console.log(`第二个请求成功-->`, value);

    value=await delay(3000)
    console.log(`第三个请求成功-->`, value);

    
  } catch (reason) {
    console.log(`任何请求失败都走这里-->`, reason);
    
  }

})() */


//3 基于Generator生成器函数,模拟Await语法,实现请求的串行效果

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()

//done:是否执行完毕  value:获取的是每一次yield后面的值「Promise实例」
/* let { done, value } = itor.next()
value.then(x => {
  //console.log(`x-->`, x);
  //x:第一个请求成功的结果 @@1000
  let { done, value } = itor.next(x) //第二次执行next,把第一个请求成功的结果 作为实参传入,目的是给上一个yield处理的返回值value赋值,所以此时输出的才能是@@1000
  value.then(x => {
    //console.log(`x-->`, x);
    //x:第2个请求成功的结果 @@2000
    let { done, value } = itor.next(x)
    value.then(x => {
      //console.log(`x-->`, x);
      //x:第3个请求成功的结果 @@2000
      let { done, value } = itor.next(x)
      //此时done为true,不需要再往下处理了
    })
  })
}) */
//可以实现,但是比较恶心,根据代码的不同,next要执行不同的次数,并且每一次都是执行next方法{第一次不传值} done为false,执行next方法,如果遇到promise实例,调用.then获得一个结果,成功之后,执行下一次,直到done为true   可以用递归和循环的方式 「while循环/递归」

//编写通知Generator中代码逐一执行的方法
const AsyncFunction = function AsyncFunction(generator,...params) {
  //params,传递给Generator函数中的值
  let itor = generator(...params)
  //基于递归的方法,通知Generator函数中的代码逐一执行
  const next = x => {
    //x 第一次不需要传值
    let { done, value } = itor.next(x)
    if (done) return
    if (!(value instanceof Promise)) value = Promise.resolve(value)
    /* value.then(x => {
      next(x)
    }) */
    value.then(next)
  }
  next()
}
AsyncFunction(handle)

/* AsyncFunction(function* (x,y){
  let total=x+y
  let value=yield total
  console.log("@1->",value);

  yield delay(2000);
  console.log("@2->",'哈哈哈');
},20,40) */

//等价于
/* (async (x,y)=>{
  let total=x+y
  let value=await total
  console.log("@1->",value);

  await delay(2000);
  console.log("@2->",'哈哈哈');

})(20,40) */






ES8 (ECMAScript 2017)中,提供了async/await语法:用来简化Promise的操作,是Promise和Generator的语法糖,上面实现的AsyncFunction函数和Generator函数的配合使用就是async/await的原理!!

低版本的Node中,无法使用async/await。
co.js这个库,在Node中使用,可以让Node环境下,出现类似于async/await的效果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值