[JS]异步/同步

本节目标

  • 导学
  • 同步代码
  • 异步代码
  • 回调地狱

导学

以下代码的执行结果是什么?

<body>
  <button class="btn">点我</button>
  <script>
    // 目标:阅读并回答代码执行和打印的顺序
    // 结果: 1, 4, 2, 点击按钮打印3
    const result = 0 + 1
    console.log(result)
    setTimeout(() => {
      console.log(2)
    }, 2000)
    document.querySelector('.btn').addEventListener('click', () => {
      console.log(3)
    })
    document.body.style.backgroundColor = 'pink'
    console.log(4)
  </script>
</body>

同步代码

正常情况下, 浏览器按照顺序执行代码, 上一行代码执行完毕再执行下一行代码 , 这就是同步代码

异步代码

异步代码提高了程序的执行效率, 调用后耗时, 但不阻塞代码继续执行, 异步任务完成后, 通过触发回调函数, 得到执行结果

举例

  • 定时器(setTimeout)/延时器(setInterval)
  • 事件函数
  • AJAX

回调地狱

多个回调函数嵌套, 就形成了回调地狱

缺点

  • 可读性差
  • 代码耦合严重
  • 捕获内部的异常困难

回调地狱

<body>
  <form>
    <span>省份:</span>
    <select>
      <option class="province"></option>
    </select>
    <span>城市:</span>
    <select>
      <option class="city"></option>
    </select>
    <span>地区:</span>
    <select>
      <option class="area"></option>
    </select>
  </form>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /**
     * 目标:演示回调函数地狱
     * 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
     * 概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
     * 缺点:可读性差,异常无法获取,耦合性严重,牵一发动全身
    */
    axios({ url: 'http://hmajax.itheima.net/api/province' }).then(({ data }) => {
      const pname = data.list[2]
      document.querySelector('.province').innerHTML = pname
      axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } }).then(({ data }) => {
        const cname = data.list[0]
        console.log(cname);
        document.querySelector('.city').innerHTML = cname
        axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } }).then(({ data }) => {
          const aname = data.list[0]
          console.log(aname);
          document.querySelector('.area').innerHTML = aname
        })
      })
    })
  </script>
</body>

链式调用

then()方法会返回一个新的Promise对象,可以继续串联下一环任务, 直到任务结束

then()方法中回调函数的返回值, 会传递给新生成的Promise对象

<body>
  <form>
    <span>省份:</span>
    <select>
      <option class="province"></option>
    </select>
    <span>城市:</span>
    <select>
      <option class="city"></option>
    </select>
    <span>地区:</span>
    <select>
      <option class="area"></option>
    </select>
  </form>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /**
     * 目标:把回调函数嵌套代码,改成Promise链式调用结构
     * 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
    */
    let pname = ''
    axios({ url: 'http://hmajax.itheima.net/api/province' }).then(({ data }) => {
      pname = data.list[3]
      document.querySelector('.province').innerHTML = pname
      return axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })

    }).then(({ data }) => {
      const cname = data.list[0]
      document.querySelector('.city').innerHTML = cname
      return axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } })

    }).then(({ data }) => {
      document.querySelector('.area').innerHTML = data.list[0]

    })
  </script>
</body>

async/await

在async函数中允许使用await关键字, 取代then函数, 等待获取Promise对象的结果, 更方便的实现链式调用

async和await是ES8引入的新语法,用来简化Promise异步操作

<body>
  <form>
    <span>省份:</span>
    <select>
      <option class="province"></option>
    </select>
    <span>城市:</span>
    <select>
      <option class="city"></option>
    </select>
    <span>地区:</span>
    <select>
      <option class="area"></option>
    </select>
  </form>
  <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
  <script>
    /**
     * 目标:掌握async和await语法,解决回调函数地狱
     * 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值
     * 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)
    */
    async function getData() {
      const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' })
      const pname = pObj.data.list[0]
      const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })
      const cname = cObj.data.list[0]
      const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } })
      const aname = aObj.data.list[0]

      document.querySelector('.province').innerHTML = pname
      document.querySelector('.city').innerHTML = cname
      document.querySelector('.area').innerHTML = aname
    }
    getData()
  </script>
</body>

try/catch

try/catch语句标记可能出错的语句,出错后捕获错误信息, 并执行catch中的代码

<script>
    /**
     * 目标:async和await_错误捕获
    */
    async function getData() {
      try {
        const pObj = await axios({ url: 'http://hmajax.itheima.net/api/province' })
        const pname = pObj.data.list[0]
        const cObj = await axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })
        const cname = cObj.data.list[0]
        const aObj = await axios({ url: 'http://hmajax.itheima.net/api/area1', params: { pname, cname } })
        const areaName = aObj.data.list[0]

        document.querySelector('.province').innerHTML = pname
        document.querySelector('.city').innerHTML = cname
        document.querySelector('.area').innerHTML = areaName
      } catch (error) {
        console.dir(error)
      }
    }

    getData()
  </script>

错误信息

  • message信息是axios返回的错误信息
  • responses信息是服务器返回的错误信息

  • 12
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值