最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • JavaScript异步发展历史

    正文概述 掘金(小和山的菜鸟们)   2021-06-10   554

    前言

    在 MDN 的 JavaScript 系列中我们已经学习了 callback、promise、generator、async/await。而在这一篇文章中,作者将以实际样例阐述异步发展历史,介绍每种实现方式的优势与不足,以期帮助读者熟悉历史进程并把握异步发展的脉络。 JavaScript异步发展历史

    异步

    几十年前的导航网站,清爽又简单,没有什么特别的功能,只是单纯的展示,现成的网页在服务器上静静躺着,高效毫无压力,让人很喜欢。

    几十年后的今天,静态页面远不能满足用户的需求,网站变得复杂起来,用户交互越来越频繁,从而产生大量复杂的内部交互,为了解决这种复杂,出现了各种系统“模式”,从而很容易的在外部获取数据,并实时展示给用户。

    获取外部数据实际上就是“网络调用”,这个时候“异步”这个词汇出现了。

    JavaScript异步发展历史

    异步 callbacks

    场景

    let readFile = (path, callBack) => {
      setTimeout(function () {
        callBack(path)
      }, 1000)
    }
    
    readFile('first', function () {
      console.log('first readFile success')
      readFile('second', function () {
        console.log('second readFile success')
        readFile('third', function () {
          console.log('third readFile success')
          readFile('fourth', function () {
            console.log('fourth readFile success')
            readFile('fifth', function () {
              console.log('fifth readFile success')
            })
          })
        })
      })
    })
    

    优点:

    • 解决了同步问题(即解决了一个任务时间长时,后面的任务排队,耗时太久,使程序的执行变慢问题)

    缺点:

    • 回调地狱(多层级嵌套),会导致逻辑混乱,耦合性高,改动一处就会导致全部变动,嵌套多时,错误处理复杂
    • 不能使用 try...catch 来抓取错误
    • 不能 return
    • 可读性差

    Promise

    场景

    let readFile = (path) => {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          if (!path) {
            reject('error!!!')
          } else {
            console.log(path + ' readFile success')
            resolve()
          }
        }, 1000)
      })
    }
    
    readFile('first')
      .then(() => readFile('second'))
      .then(() => readFile('third'))
      .then(() => readFile('fourth'))
      .then(() => readFile('fifth'))
    

    优点:

    • 状态改变后,就不会再变,任何时候都可以得到这个结果
    • 可以将异步操作以同步操作的流程表达出来,避免了层层嵌套的回调函数
    • 一定程度上解决了回调地狱的可读性问题

    缺点:

    • 无法取消 promise
    • 当处于 pending 状态时,无法得知目前进展到哪一个阶段
    • 代码冗余,有一堆任务时也会使语义不清晰

    Generator

    特征

    • function 与函数名之间带有(*)
    • 函数体内部使用 yield 表达式,函数执行遇到 yield 就返回

    场景

    var readFile = function (name, ms) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(name + '读完了')
          resolve()
        }, ms)
      })
    }
    
    var gen = function* () {
      console.log('指定generator')
      yield readFile('first', 1000)
      yield readFile('second', 2000)
      yield readFile('third', 3000)
      yield readFile('forth', 4000)
      yield readFile('fifth', 5000)
      return '完成了'
    }
    var g = gen()
    var result = g.next()
    result.value
      .then(() => {
        g.next()
      })
      .then(() => {
        g.next()
      })
      .then(() => {
        g.next()
      })
      .then(() => {
        g.next()
      })
    

    优点:

    • 可以控制函数的执行,可以配合 co 函数库使用

    缺点:

    • 流程管理却不方便(即何时执行第一阶段、何时执行第二阶段)

    async 和 await

    JavaScript异步发展历史

    场景 1

    var readFile = function (name, ms) {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          console.log(name + '读完了')
          resolve()
        }, ms)
      })
    }
    
    async function useAsyncAwait() {
      await readFile('first', 1000)
      await readFile('second', 2000)
      await readFile('third', 3000)
      await readFile('forth', 4000)
      await readFile('fifth', 5000)
      console.log('async文件阅读完毕')
    }
    useAsyncAwait()
    

    优点

    • 内置执行器。意味着不需要像 generator 一样调用 next 函数或 co 模块

    • 更广的适用性。async 和 await 后面跟的都是 promise 函数,原始数据类型会被转为 promise

    • 语义更清晰、简洁

      缺点

    • 大量的 await 代码会阻塞(程序并不会等在原地,而是继续事件循环,等到响应后继续往下走)程序运行,每个 await 都会等待前一个完成

    场景 2 场景 1 中的代码,其实 second,third 的伪请求其实并不依赖于 first,second 的结果,但它们必须等待前一个的完成才能继续,而我们想要的是它们同时进行,所以正确的操作应该是这样的。

    async function useAsyncAwait() {
      const first = readFile('first', 1000)
      const second = readFile('second', 2000)
      const third = readFile('third', 3000)
      const forth = readFile('forth', 4000)
      const fifth = readFile('fifth', 5000)
      console.log('async文件阅读完毕')
    
      await first
      await second
      await third
      await forth
      await fifth
    }
    useAsyncAwait()
    

    在这里,我们将三个 promise 对象存储在变量中,这样可以同时启动它们关联的进程。

    总结

    在这篇文章中,我们已经介绍了 JavaScript 异步发展史中 --- callback、promise、generator、async/await 的使用方式、优点与缺点。

    发展史优点缺点
    callback解决了同步问题回调地狱、可读性差、无法 try / catch 、无法 returnpromise一定程度上解决了回调地狱的可读性无法取消、任务多时,同样存在语义不清晰generator可以控制函数的执行,可以配合 co 函数库使用流程管理却不方便(即何时执行第一阶段、何时执行第二阶段async/await语义更清晰、简洁,内置执行器认知不清晰可能会造成大量 await 阻塞(程序并不会等在原地,而是继续事件循环,等到响应后继续往下走)情况

    而在现有的异步解决方案中,async/await 是使用人数最多的,它带给我们最大的好处即同步代码的风格,语义简洁、清晰。

    相关文章

    • MDN-异步 JavaScript
    • 阮一峰-JavaScript 异步编程的 4 种方法
    • 掘金-细说 JavaScript 异步的发展历程
    • 掘金-async/await 的优点、陷阱以及如何使用
    • JS 异步发展流程

    起源地下载网 » JavaScript异步发展历史

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元