Generator

ES6 新引入了 Generator 函数,可以通过 yield 关键字,把函数的执行流挂起,为改变执行流程提供了可能,从而为异步编程提供解决方案。

Generator 有两个区分于普通函数的部分:

  • 在 function 后面,函数名之前有个 *
  • 函数内部有 yield 表达式

基本使用

function * foo() {
  console.log('t1')
}

// 函数调用会返回一个遍历器对象
const ga = foo()

此时,执行node generator.js,得不到任何结果

function * foo() {
  console.log('t1')
}

// 函数调用会返回一个遍历器对象
const ga = foo()
ga.next()

多写一句ga.next(),再执行node generator.js,就能打印出t1来了

yield关键字

function * foo() {
  console.log('t1')
  yield 'yyyyy'
  console.log('t2')
}
const ga = foo()
ga.next()

执行node generator.js,只打印出了t1,没打印出t2,这是为什么呢?因为我们在使用遍历器对象ga去调用next方法时,最终只会执行到yield的位置。后面的代码是不会被执行到的

因此,yield被称为“暂停”

遍历器最大的特点,就是让函数能有一个“暂停”的功能

想要让t2被打印出来怎么办?

在ga.next()后面再写一句ga.next()

ga.next()的返回值

ga就是遍历器对象

function * foo() {
  console.log('t1')
  yield 'yyyyy'
  console.log('t2')
}
const ga = foo()
const yd = ga.next()
console.log(yd)

打印出

t1
{ value: ‘yyyyy’, done: false }

value就是前面执行yield的结果

done为false,表示foo有没有执行完(这里还有一句console.log(‘t2’)没执行,需要你再写一句ga.next()才能执行。但如果你把ga.next()写到console.log(yd)后面,那么执行到yd这一句时,也会打印出done:false)

const ga = foo()
const yd = ga.next()
console.log(yd)
const yd2 = ga.next()
console.log(yd2)

打印出

t1
{ value: ‘yyyyy’, done: false }
t2
{ value: undefined, done: true }

ga.next()的参数

function * foo() {
  console.log('t1')
  const v = yield 'yyyyy'
  console.log(v)
  console.log('t2')
}
const ga = foo()
const yd = ga.next()
console.log(yd)
const yd2 = ga.next('444')
console.log(yd2)

我们给ga.next()传参的目的,就是下一次调用next()时,可以在yield那里接收返回值。在上面的代码中,第一个ga.next()执行的是yield右边的内容(‘yyyyy’),第二个ga.next()会从yield的左边开始执行。若yield左边没有代码,就从yield的下一行代码开始执行

打印出

t1
{ value: ‘yyyyy’, done: false }
444
t2
{ value: undefined, done: true }

Generator的作用

通过以上分析,可以发现Generator的最大作用是“暂停”。我们可以让异步代码执行时,若还没得到结果,就先暂停下来

先引入封装好的myAjax方法

<script src="./9.promiseAjax.js"></script>

再写js逻辑

function * foo() {
  yield myAjax('https://jsonplaceholder.typicode.com/comments?id=2')
  yield myAjax('https://jsonplaceholder.typicode.com/comments?id=3')
}
var ga = foo()
var yd1 = ga.next()
console.log(yd1)
// 打印出的yd1为 { value: Promise(一堆内容), done: false }

接下来就可以通过Promise实例对象的.then方法,得到第一个ajax请求返回的响应结果。然后再调用ga.next(),再执行foo()里面的第二个ajax请求,

yd1.value.then( data => {
  console.log(data)
  var yd1 = ga.next()
  yd1.value.then( data => {
    console.log(data)
  })
})

若有很多很多个yield ajax…,就需要用递归做封装了

function co(foo) {
  var ga = foo()
  function handler(res) {
    if (res.done) return
    res.value.then( data => {
      console.log(data)
      handler(ga.next())
    })
  }
  handler(ga.next())
}

co(generatorAjax)

generatorAjax的逻辑这么来写:

function * generatorAjax() {
  yield myAjax('https://jsonplaceholder.typicode.com/comments?id=2')
  yield myAjax('https://jsonplaceholder.typicode.com/comments?id=3')
}

是不是有点像 async await的写法

async function generatorAjax() {
  await myAjax('https://jsonplaceholder.typicode.com/comments?id=2')
  await myAjax('https://jsonplaceholder.typicode.com/comments?id=3')
}

其实async await就是语法糖,内部就是用Generator来实现的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值