当前位置: 首页 > article >正文

AJAX笔记进阶篇

黑马程序员视频地址:

AJAX-Day04-01.同步代码和异步代码https://www.bilibili.com/video/BV1MN411y7pw?vd_source=0a2d366696f87e241adc64419bf12cab&spm_id_from=333.788.videopod.episodes&p=47

同步代码和异步代码


回调函数地狱与解决方法

回调函数地狱

需求:展示默认第一个省,第一个城市,第一个地区在下拉菜单中
概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
缺点:可读性差,异常无法通过一次代码捕获,耦合性严重,牵一发动全身

/**
     * 目标:演示回调函数地狱
     * 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
     * 概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱
     * 缺点:可读性差,异常无法写一次代码获取,耦合性严重,牵一发动全身
    */
    // 1. 获取默认第一个省份的名字
    axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {
      const pname = result.data.list[0]
      document.querySelector('.province').innerHTML = pname
      // 2. 获取默认第一个城市的名字
      axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }}).then(result => {
        const cname = result.data.list[0]
        document.querySelector('.city').innerHTML = cname
        // 3. 获取默认第一个地区的名字
        axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }}).then(result => {
          console.log(result)
          const areaName = result.data.list[0]
          document.querySelector('.area').innerHTML = areaName
        })
      })
    }).catch(error => {
      console.dir(error) //无法通过一次catch捕获任意一个axios错误
    })

解决方法一:Promise 链式调用 

deepseek给出的解释:

Promise 链式调用:通过 Promise 状态(Pending/Fulfilled/Rejected)的不可变性,严格保证执行顺序。

Promise 的 then() 方法调用后会返回一个新的 Promise 对象。这是 Promise 链式调用的核心机制。以下是关键点解释:


1. 返回一个新的 Promise

  • 原 Promise 不受影响:调用 then() 不会修改原始的 Promise 对象,而是生成一个新的 Promise。

  • 链式调用的基础:正是通过返回新 Promise,才能继续调用下一个 .then() 或 .catch(),形成链式结构。

 

2. 新 Promise 的状态由回调决定

  • 回调返回值决定状态:新 Promise 的状态(fulfilled 或 rejected)和值,由 then() 中传入的回调函数决定:

    • 如果回调返回普通值(非 Promise),新 Promise 会以该值变为 fulfilled

    • 如果回调返回一个新的 Promise,新 Promise 会“跟随”这个返回的 Promise 的状态。

    • 如果回调抛出错误,新 Promise 会变为 rejected

博主重述:调用一次axios时,基于axios内部代码,会自动new一个promise对象,并且执行内部代码,成功会调用resolve()方法,此时原promise对象被标记为成功,然后会自动调用then方法,并且返回一个新对象,而新对象的标记与返回值有关,若返回值也为一个新promise对象,则会与其的标志保持一致,此时如果新对象执行成功(即调用resolve()方法),则会被标记为成功,从而执行then方法,如此循环,一级一级读取then方法,倘若某一级的promise对象被标记失败,则会找catch方法,即跳过其他then而直接到最后一行找catch

/**
     * 目标:把回调函数嵌套代码,改成Promise链式调用结构
     * 需求:获取默认第一个省,第一个市,第一个地区并展示在下拉菜单中
    */
    let pname = ''
    // 1. 得到-获取省份Promise对象
    axios({url: 'http://hmajax.itheima.net/api/province'}).then(result => {
      pname = result.data.list[0]
      document.querySelector('.province').innerHTML = pname
      // 2. 得到-获取城市Promise对象
      return axios({url: 'http://hmajax.itheima.net/api/city', params: { pname }})
    }).then(result => {
      const cname = result.data.list[0]
      document.querySelector('.city').innerHTML = cname
      // 3. 得到-获取地区Promise对象
      return axios({url: 'http://hmajax.itheima.net/api/area', params: { pname, cname }})
    }).then(result => {
      console.log(result)
      const areaName = result.data.list[0]
      document.querySelector('.area').innerHTML = areaName
    }).catch(error => {console.log(error)})//一次catch捕获即可获取任意某一次axios错误

解决方法二:async 和await 使用

async:标记函数为异步,使其支持 await。普通声明函数为同步函数
await:暂停异步函数,等待异步操作完成,让代码逻辑更清晰。

await 会暂停当前 async 函数的执行,但不会阻塞线程。其他代码(如事件循环)可以继续运行。 

    /**
     * 目标:掌握async和await语法,解决回调函数地狱
     * 概念:在async函数内,使用await关键字,获取Promise对象"成功状态"结果值
     * 注意:await必须用在async修饰的函数内(await会阻止"异步函数内"代码继续执行,原地等待结果)
    */
    // 1. 定义async修饰函数
    async function getData() {
      // 2. await等待Promise对象成功的结果,同时会返回promise对象成功执行返回的值(即then里的result)
      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 areaName = aObj.data.list[0]


      document.querySelector('.province').innerHTML = pname
      document.querySelector('.city').innerHTML = cname
      document.querySelector('.area').innerHTML = areaName
    }

    getData()

捕获错误:

    /**
     * 目标:async和await_错误捕获
    */
    async function getData() {
      // 1. try包裹可能产生错误的代码
      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/area', 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) {
        // 2. 接着调用catch块,接收错误信息
        // 如果try里某行代码报错后,try中剩余的代码不会执行了
        console.dir(error)
      }
    }

    getData()

事件循环-EventLoop

1. 什么是事件循环?

➢ 执行代码和收集异步任务,在调用栈空闲时,反复调用任务队列里 回调函数执行机制

2. 为什么有事件循环?

➢ JavaScript 是单线程的,为了不阻塞JS 引擎,设计执行代码的模型

3. JavaScript 内代码如何执行?

➢ 执行同步代码,遇到异步代码交给宿主浏览器环境执行

➢ 异步有了结果后,把回调函数放入任务队列排队

➢ 当调用栈空闲后,反复调用任务队列里的回调函数 


宏任务与微任务


Promise.all静态方法

    // 1. 请求城市天气,得到Promise对象
    const bjPromise = axios({url: "http://hmajax.itheima.net/api/weather", params: {city: "110100"}})
    const shPromise = axios({url: "http://hmajax.itheima.net/api/weather", params: {city: "310100"}})
    const gzPromise = axios({url: "http://hmajax.itheima.net/api/weather", params: {city: "440100"}})
    const szPromise = axios({url: "http://hmajax.itheima.net/api/weather", params: {city: "440300"}})

    // 2. 使用Promise.all,合并多个Promise对象
    const p = Promise.all([bjPromise, shPromise, gzPromise, szPromise])

    p.then(result => {
      // 注意:结果数组顺序和合并时顺序是一致
      console.log(result)
    }).catch(error => {
      console.log(error)
    })

http://www.kler.cn/a/531067.html

相关文章:

  • Leetcode 8283 移除排序链表中的重复元素
  • 数据结构之栈和队列(超详解)
  • FFmpeg源码:av_base64_decode函数分析
  • 人工智能学习(四)之机器学习基本概念
  • python学习——函数的返回值
  • C++并发编程指南08
  • 《使用Ollama部署DeepSeek并进行对话全过程记录》
  • Spring 面试题【每日20道】【其二】
  • 11.1 LangChain Chains 最佳实践:从流水线设计到生产部署的全链路指南
  • 35.Word:公积金管理中心文员小谢【37】
  • string例题
  • MYSQL性能调优连接器、查询缓存、分析器、优化器、执行器、一图详解MYSQL底层工作原理
  • 泰山Office开源计划
  • 机试题——字符匹配
  • Python的那些事第十篇:隐藏细节与提供接口的艺术Python中的封装
  • Leetcode—598. 区间加法 II【简单】
  • golang命令大全7--性能优化与分析
  • Vue - readonly 与 shallowReadonly
  • 模拟实战-用CompletableFuture优化远程RPC调用
  • 【优先算法】专题——位运算
  • 存储器知识点2
  • 基础IO的学习
  • 代码随想录-训练营-day18
  • 【go语言】grpc 快速入门
  • 30分钟入门CompletableFuture并发工具使用
  • 【漫话机器学习系列】077.范数惩罚是如何起作用的(How Norm Penalties Work)