JS中生成器处理异步的方案

导读:本篇文章讲解 JS中生成器处理异步的方案,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

生成器异步处理

普通处理方案

学完了我们前面的Promise、生成器等,我们目前通过一个案例来看一下异步代码的处理方案。

案例需求 :

  • 我们需要向服务器发送网络请求获取数据,一共需要发送三次请求
  • 第二次的请求url依赖于第一次的结果;
  • 第三次的请求url依赖于第二次的结果, 依次类推;

方式一 : 层层嵌套(回调地狱)

// 封装函数模拟网络请求
function requestDate(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(url)
    }, 2000)
  })
}

function getData() {
  // 发送第一次网络请求
  requestDate("aaa").then(res1 => {
    console.log("第一次网络请求的结果:", res1) // aaa
    // 发送第二次网络请求
    requestDate(res1 + "bbb").then(res2 => {
      console.log("第二次网络请求的结果:", res2) // aaabbb
      // 发送第三次网络请求
      requestDate(res2 + "ccc").then(res3 => {
        console.log("第三次网络请求的结果:", res3) // aaabbbccc
      })
    })
  })
}
getData()

方式二: 使用Promise进行优化, 解决回调地狱(链式编程)

// 封装函数模拟网络请求
function requestDate(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(url)
    }, 2000)
  })
}

function getData() {
  requestDate("aaa").then(res1 => {
    console.log("第一次网络请求的结果:", res1) // aaa
    return requestDate(res1 + "bbbb")
  }).then(res2 => {
    console.log("第二次网络请求的结果:", res2) // aaabbb
    return requestDate(res2 + "ccc")
  }).then(res3 => {
    console.log("第三次网络请求的结果:", res3) // aaabbbccc
  })
}
getData()

生成器方案

上面的代码即使方式二使用Promise对代码进行了重构, 但是代码看起来也是阅读性依然比较差的,有没有办法可以继续来对上面的代码进行优化呢?

  • 方式三: 利用生成器再进一步的优化
// 封装函数模拟网络请求
function requestDate(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(url)
    }, 2000)
  })
}

function* getData() {
  const res1 = yield requestDate("aaa")
  console.log("res1", res1) // aaa
  const res2 = yield requestDate(res1 + "bbb")
  console.log("res2", res2) // aaabbb
  const res3 = yield requestDate(res2 + "ccc")
  console.log("res3:", res3) // aaabbbccc
}

const generator = getData()
// 因为生成器的next方法返回的对象中的value值是返回的Promise
// 我们可以通过Promise的then拿到第一次网络请求的结果res1
generator.next().value.then(res1 => {
  // 将第一次网络请求的结果传入生成器函数时, 可以拿到第二次网络请求的结果
  generator.next(res1).value.then(res2 => {
    // 将第二次网络请求的结果传入生成器函数, 可以拿到第三次网络请求的结果
    generator.next(res2).value.then(res3 => {
      // 将第三次网络请求的结果传入生成器函数
      generator.next(res3)
    })
  })
}) 

目前我们的方案三写法有两个问题:

  • 第一,我们不能确定到底需要调用几层的Promise关系;
  • 第二,如果还有其他需要这样执行的函数,我们应该如何操作呢?

所以,我们可以封装一个工具函数execGenerator自动执行生成器函数(了解):

// 封装模拟网络请求的函数
function requestData(url) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve(url)
    }, 2000)
  })
}

// 生成器的处理方案
function* getData() {
  const res1 = yield requestData("why")
  console.log("res1:", res1)

  const res2 = yield requestData(res1 + "kobe")
  console.log("res2:", res2)

  const res3 = yield requestData(res2 + "james")
  console.log("res3:", res3)

  const res4 = yield requestData(res3 + "curry")
  console.log("res4:", res4)

  const res5 = yield requestData(res4 + "tatumu")
  console.log("res5:", res5)
}

// 自动化执行生成器函数(了解)
function execGenFn(genFn) {
  // 1.获取对应函数的generator
  const generator = genFn()
  // 2.定义一个递归函数
  function exec(res) {
    const result = generator.next(res)
    if (result.done) return
    result.value.then(res => {
      exec(res)
    })
  }
  // 3.执行递归函数
  exec()
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/120128.html

(0)
seven_的头像seven_bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!