ES6生成器与async-await解析

ES6生成器与async/await内容解析

什么是生成器?

​ 生成器是ES6中新增的一种函数控制、使用的方案,它可以让我们更加灵活的控制函数什么时候继续执行、暂停执行等。平时我们会编写很多的函数,这些函数终止的条件通常是返回值或者发生了异常。

生成器函数也是一个函数,但是和普通的函数有一些区别:

  • 首先,生成器函数需要在function的后面加一个符号:*
  • 其次,生成器函数可以通过yield关键字来控制函数的执行流程:
  • 最后,生成器函数的返回值是一个Generator(生成器):
    • 生成器事实上是一种特殊的迭代器;
    • MDN:Instead, they return a special type of iterator, called a Generator.

生成器函数执行

我们发现上面的生成器函数foo的执行体压根没有执行,它只是返回了一个生成器对象。

  • 那么我们如何可以让它执行函数中的东西呢?调用next即可;
  • 我们之前学习迭代器时,知道迭代器的next是会有返回值的;
  • 但是我们很多时候不希望next返回的是一个undefined,这个时候我们可以通过yield来返回结果;

在这里插入图片描述

生成器传递参数 – next函数

函数既然可以暂停来分段执行,那么函数应该是可以传递参数的,我们是否可以给每个分段来传递参数呢?

  • 答案是可以的;
  • 我们在调用next函数的时候,可以给它传递参数,那么这个参数会作为上一个yield语句的返回值;
  • 注意:也就是说我们是为本次的函数代码块执行提供了一个值;

在这里插入图片描述

生成器提前结束 – return函数

​ 还有一个可以给生成器函数传递参数的方法是通过return函数**:return传值后这个生成器函数就会结束,之后调用next不会继续生成值了。**

function* foo(num) {
  console.log("函数开始执行~")

  const value1 = 100 * num
  console.log("第一段代码:", value1)
  const n = yield value1

  const value2 = 200 * n
  console.log("第二段代码:", value2)
  const count = yield value2

  console.log("函数执行结束~")
  return "123"
}

const generator = foo(10)

console.log(generator.next())

// 第二段代码的执行, 使用了return
// 那么就意味着相当于在第一段代码的后面加上return, 就会提前终端生成器函数代码继续执行
console.log(generator.return(15))
console.log(generator.next())
console.log(generator.next())

生成器抛出异常 – throw函数

除了给生成器函数内部传递参数之外,也可以给生成器函数内部抛出异常:

  • 抛出异常后我们可以在生成器函数中捕获异常;
  • 但是在catch语句中不能继续yield新的值了,但是可以在catch语句外使用yield继续中断函数的执行;
function* foo() {
  console.log("代码开始执行~")

  const value1 = 100
  try {
    yield value1
  } catch (error) {
    console.log("捕获到异常情况:", error)

    yield "abc"
  }

  console.log("第二段代码继续执行")
  const value2 = 200
  yield value2

  console.log("代码执行结束~")
}

const generator = foo()
const result = generator.next()
generator.throw("error message")

// const result = generator.next()

生成器替代迭代器

// 1.生成器来替代迭代器
function* createArrayIterator(arr) {
  // 第一种写法
  // for(let i=0;i<arr.length;i++){
  //   yield arr[i]
  // }

  // 第二种写法
  // for(let item of arr){
  //   yield item
  // }

  // 第三种写法
  // yield* arr

}

// const names=['abc','cba','nba']
// const namesIterator=createArrayIterator(names)

// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())
// console.log(namesIterator.next())

// 2.创建一个函数,这个函数可以迭代一个范围内的数字
//10 20
function* createRangeIterator(start, end) {
  let index = start
  while (index < end) {
    yield index++
  }

  // let index = start
  // return {
  //   next: function() {
  //     if (index < end) {
  //       return { done: false, value: index++ }
  //     } else {
  //       return { done: true, value: undefined }
  //     }
  //   }
  // }
}

// const rangeIterator = createRangeIterator(10, 20)
// console.log(rangeIterator.next())
// console.log(rangeIterator.next())
// console.log(rangeIterator.next())
// console.log(rangeIterator.next())

// 3.class案例
class ClassRome{
  constructor(address,name,students){
    this.address=address
    this.name=name
    this.students=students
  }

  entry(newStudent){
    this.students.push(newStudent)
  }

  *[Symbol.iterator](){
    yield* this.students
  }
}

const classRome=new ClassRome('beijing','liu',['james','kobe','curry'])
for(let item of classRome){
  console.log(item)
}

异步处理方案

//request.js
function requestData(url){
  return new Promise((resolve,reject)=>{
    setTimeout(()=>{
      resolve(url)
    },2000)
  })
}

// 需求
// 1 > url:liu -> res:liu
// 2 > url:res + 'aaa'-> res:liuaaa
// 3 > url:res + 'bbb'-> res:liuaaabbb

// 1.第一种方案:回调地狱
// requestData('liu').then(res=>{
//   requestData(res+'aaa').then(res=>{
//     requestData(res+'bbb').then(res=>{
//       console.log(res)
//     })
//   })
// })

// 2.第二种方案:Promise中的then
// requestData('liu').then(res=>{
//   return requestData(res+'aaa')
// }).then(res=>{
//   return requestData(res+'bbb')
// }).then(res=>{
//   console.log(res)
// })

// 3.第三种方案:Promise+generator
function* getData(){
  const res1=yield requestData('liu')
  const res2=yield requestData(res1+'aaa')
  const res3=yield requestData(res2+'bbb')
  console.log(res3)
}

// 1 > 手动执行生成器函数
// const generator=getData()
// generator.next().value.then(res=>{
//   generator.next(res).value.then(res=>{
//     generator.next(res).value.then(res=>{
//       generator.next(res)
//     })
//   })
// })

// 2.自己封装一个自动执行的函数
// function execGenerator(getFn){
//   const generator=getFn()
//   function exec(res){
//     const result=generator.next(res)
//     if(result.done){
//       return result.value
//     }
//     result.value.then(res=>{
//       exec(res)
//     })
//   }

//   exec()
// }

// execGenerator(getData)

// 3> 第三方包co自动执行
const co=require('co')
co(getData)

// 4.第四种方案:async/await
// async function getData(){
//   const res1=await requestData('liu')
//   const res2=await requestData(res1+'aaa')
//   const res3=await requestData(res2+'bbb')
//   console.log(res3)
// }
// getData()

异步函数 async function

async关键字用于声明一个异步函数:

  • async是asynchronous单词的缩写,异步、非同步;
  • sync是synchronous单词的缩写,同步、同时;

async异步函数可以有很多中写法:

在这里插入图片描述

异步函数的执行流程

异步函数的内部代码执行过程和普通的函数是一致的,默认情况下也是会被同步执行。

异步函数有返回值时,和普通函数会有区别:

  • 情况一:异步函数也可以有返回值,但是异步函数的返回值会被包裹到Promise.resolve中;
  • 情况二:如果我们的异步函数的返回值是Promise,Promise.resolve的状态会由Promise决定;
  • 情况三:如果我们的异步函数的返回值是一个对象并且实现了thenable,那么会由对象的then方法来决定;

如果我们在async中抛出了异常,那么程序它并不会像普通函数一样报错,而是会作为Promise的reject来传递;

await关键字

async函数另外一个特殊之处就是可以在它内部使用await关键字,而普通函数中是不可以的。

await关键字有什么特点呢?

  • 通常使用await是后面会跟上一个表达式,这个表达式会返回一个Promise;

  • 那么await会等到Promise的状态变成fulfilled状态,之后继续执行异步函数;

  • 如果await后面是一个普通的值,那么会直接返回这个值;

  • 如果await后面是一个thenable的对象,那么会根据对象的then方法调用来决定后续的值;
    程序它并不会像普通函数一样报错,而是会作为Promise的reject来传递;

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值