# 模拟网络请求

  • 网络需求:

    • url: https://neko -> res: https://neko

    • url: https://neko + "aimer" -> res: https://nekoaimer

    • url: https://nekoaimer + ".com" -> res: https://nekoaimer.com

# 回调地狱问题

  • 这种代码阅读性极差
// 网络请求
function requsetDate(url) {
  return new Promise(resolve => setTimeout(() => resolve(url), 2000))
}
// 回调地狱
requsetDate('https://neko')
.then(res => {
  requsetDate(res).then(res => {
    requsetDate(res + 'aimer').then(res => {
      requsetDate(res + '.com').then(res => {
        console.log(res) // https://nekoaimer.com
      })
    })
  })
})

# 优化方案

  • Promise then 方法的返回值也是 Promise, 那么我们可以 return 出去
  • 这种方式就要清晰不少,但依然不是我认为最好的处理的方案或者说是结果
// 网络请求
function requsetDate(url) {
  return new Promise(resolve => setTimeout(() => resolve(url), 2000))
}
requsetDate('https://neko')
.then(res => {
    return requsetDate(res + 'aimer')
})
.then(res => {
  return requsetDate(res + '.com')
})
.then(res => {
  console.log(res) // https://nekoaimer.com
})

# Promise + generator 方案

  • 这种方案从 getData () 能够清晰的得出每次结果
// 网络请求
function requsetDate(url) {
  return new Promise(resolve => setTimeout(() => resolve(url), 2000))
}
// 这种结构每次网络请求就会看的非常清晰
function* getData() {
  const res1 = yield requsetDate('https://neko')
  console.log(res1) // https://neko
  const res2 = yield requsetDate(res1 + 'aimer') 
  console.log(res2) // https://nekoaimer
  const res3 = yield requsetDate(res2 + '.com') 
  console.log(res3) // https://nekoaimer.com
}
// generator
const generator = getData()
generator.next().value.then(res => {
  generator.next(res).value.then(res => {
    generator.next(res).value.then(res => {
      generator.next(res)
    })
  })
})
  • 那么有人可能会有疑问了,下面的 generator 不也是回调地狱吗,代码量看上去更麻烦了呀?
  • 别急,我会进行一些处理,之后就会发现这种处理方式结构清晰,可重复利用是非常优秀的

# 自动执行 generator 函数

// 网络请求
function requsetDate(url) {
  return new Promise(resolve => setTimeout(() => resolve(url), 2000))
}
// 封装了一个自动执行的函数
function execGenerator(genFn) {
  const generator = genFn()
  function  exec(res) {
    const result = generator.next(res)
    if (result.done) return result.value
    result.value.then(res => exec(res))
  }
  exec()
}
//generator 方式代码清晰明了
function* getData() {
  const res1 = yield requsetDate('https://neko')
  const res2 = yield requsetDate(res1 + 'aimer')
  const res3 = yield requsetDate(res2 + '.com')
  console.log(res3) // https://nekoaimer.com
}
execGenerator(getData)

# co(TJ)

  • 安装 co 包
npm install co
  • 这个包实现的功能与上面的类似 所以可直接引入进来
function requsetDate(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(url), 2000)
  })
}
function* getData() {
  const res1 = yield requsetDate('https://neko')
  const res2 = yield requsetDate(res1 + 'aimer')
  const res3 = yield requsetDate(res2 + '.com')
  console.log(res3) // https://nekoaimer.com
}
const co = require('co')
co(getData)

# async & await 实现

  • 这种方案本质上是 generator 与 Promise 的语法糖
  • 所以最终的解决方案就是下面这种了
function requsetDate(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(url), 2000)
  })
}
async function getData() {
  const res1 = await requsetDate('https://neko')
  const res2 = await requsetDate(res1 + 'aimer')
  const res3 = await requsetDate(res2 + '.com')
  console.log(res3) // https://nekoaimer.com
}
getData()