AJAX-2 AJAX原理

AJAX-2 AJAX原理

01.XMLHttpRequest - 基础使用

  1. AJAX 是浏览器与服务器通信的技术,采用 XMLHttpRequest 对象相关代码

  2. axios 是对 XHR 相关代码进行了封装,让我们只关心传递的接口参数

  3. 学习 XHR 也是了解 axios 内部与服务器交互过程的真正原理

    image-20230221182835545

  4. 语法如下:

    1
    2
    3
    4
    5
    6
    7
    const xhr = new XMLHttpRequest()
    xhr.open('请求方法', '请求url网址')
    xhr.addEventListener('loadend', () => {
    // 响应结果
    console.log(xhr.response)
    })
    xhr.send()

    image-20230221183057392

  5. 需求:以一个需求来体验下原生 XHR 语法,获取所有省份列表并展示到页面上

  6. 代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    <!DOCTYPE html>
    <html lang="en">

    <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>XMLHttpRequest_基础使用</title>
    </head>

    <body>
    <p class="my-p"></p>
    <script>
    /**
    * 目标:使用XMLHttpRequest对象与服务器通信
    * 1. 创建 XMLHttpRequest 对象
    * 2. 配置请求方法和请求 url 地址
    * 3. 监听 loadend 事件,接收响应结果
    * 4. 发起请求
    */
    // 1. 创建 XMLHttpRequest 对象
    const xhr = new XMLHttpRequest()

    // 2. 配置请求方法和请求 url 地址
    xhr.open('GET', 'http://hmajax.itheima.net/api/province')

    // 3. 监听 loadend 事件,接收响应结果
    xhr.addEventListener('loadend', () => {
    console.log(xhr.response)
    const data = JSON.parse(xhr.response)
    console.log(data.list.join('<br>'))
    document.querySelector('.my-p').innerHTML = data.list.join('<br>')
    })

    // 4. 发起请求
    xhr.send()
    </script>
    </body>

    </html>

02.XMLHttpRequest - 查询参数

  1. 什么是查询参数:携带额外信息给服务器,返回匹配想要的数据

  2. 查询参数原理要携带的位置和语法:http://xxxx.com/xxx/xxx?参数名1=值1&参数名2=值2

  3. 所以,原生 XHR 需要自己在 url 后面携带查询参数字符串,没有 axios 帮助我们把 params 参数拼接到 url 字符串后面了

  4. 需求:查询河北省下属的城市列表

    image-20230404133429378

  5. 核心代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    /**
    * 目标:使用XHR携带查询参数,展示某个省下属的城市列表
    */
    const xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://hmajax.itheima.net/api/city?pname=辽宁省')
    xhr.addEventListener('loadend', () => {
    console.log(xhr.response)
    const data = JSON.parse(xhr.response)
    console.log(data)
    document.querySelector('.city-p').innerHTML = data.list.join('<br>')
    })
    xhr.send()

04.XMLHttpRequest - 数据提交

  1. 了解原生 XHR 进行数据提交的方式

  2. 需求:通过 XHR 完成注册用户功能

    image-20230404135245271
  3. 步骤和语法:

    1. 注意1:但是这次没有 axios 帮我们了,我们需要自己设置请求头 Content-Type:application/json,来告诉服务器端,我们发过去的内容类型是 JSON 字符串,让他转成对应数据结构取值使用

    2. 注意2:没有 axios 了,我们前端要传递的请求体数据,也没人帮我把 JS 对象转成 JSON 字符串了,需要我们自己转换

    3. 注意3:原生 XHR 需要在 send 方法调用时,传入请求体携带

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      const xhr = new XMLHttpRequest()
      xhr.open('请求方法', '请求url网址')
      xhr.addEventListener('loadend', () => {
      console.log(xhr.response)
      })

      // 1. 告诉服务器,我传递的内容类型,是 JSON 字符串
      xhr.setRequestHeader('Content-Type', 'application/json')
      // 2. 准备数据并转成 JSON 字符串
      const user = { username: 'itheima007', password: '7654321' }
      const userStr = JSON.stringify(user)
      // 3. 发送请求体数据
      xhr.send(userStr)
  4. 核心代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    * 目标:使用xhr进行数据提交-完成注册功能
    */
    document.querySelector('.reg-btn').addEventListener('click', () => {
    const xhr = new XMLHttpRequest()
    xhr.open('POST', 'http://hmajax.itheima.net/api/register')
    xhr.addEventListener('loadend', () => {
    console.log(xhr.response)
    })

    // 设置请求头-告诉服务器内容类型(JSON字符串)
    xhr.setRequestHeader('Content-Type', 'application/json')
    // 准备提交的数据
    const userObj = {
    username: 'itheima007',
    password: '7654321'
    }
    const userStr = JSON.stringify(userObj)
    // 设置请求体,发起请求
    xhr.send(userStr)
    })

05.认识_Promise

  1. 什么是 Promise ?

    • Promise 对象用于表示一个异步操作的最终完成(或失败)及其结构值
  2. Promise 的好处是什么?

    • 逻辑更清晰(成功或失败会关联后续的处理函数)

    • 了解 axios 函数内部运作的机制

      image-20230222113651404

    • 能解决回调函数地狱问题(后面会讲到),今天先来看下它的基础使用

  3. Promise 管理异步任务,语法怎么用?

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 1. 创建 Promise 对象
    const p = new Promise((resolve, reject) => {
    // 2. 执行异步任务-并传递结果
    // 成功调用: resolve(值) 触发 then() 执行
    // 失败调用: reject(值) 触发 catch() 执行
    })
    // 3. 接收结果
    p.then(result => {
    // 成功
    }).catch(error => {
    // 失败
    })
  4. 示例代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    /**
    * 目标:使用Promise管理异步任务
    */
    // 1. 创建Promise对象
    const p = new Promise((resolve, reject) => {
    // 2. 执行异步代码
    setTimeout(() => {
    // resolve('模拟AJAX请求-成功结果')
    reject(new Error('模拟AJAX请求-失败结果'))
    }, 2000)
    })

    // 3. 获取结果
    p.then(result => {
    console.log(result)
    }).catch(error => {
    console.log(error)
    })

06.认识_Promise 的状态

  1. 为什么要了解 Promise 的三种状态 ?

    • 知道 Promise 对象如何关联的处理函数,以及代码的执行顺序
  2. Promise 有哪三种状态?

    每个 Promise 对象必定处于以下三种状态之一

    1. 待定(pending):初始状态,既没有被兑现,也没有被拒绝
    2. 已兑现(fulfilled):操作成功完成
    3. 已拒绝(rejected):操作失败

    状态的英文字符串,可以理解为 Promise 对象内的字符串标识符,用于判断什么时候调用哪一个处理函数

  3. Promise 的状态改变有什么用:调用对应函数,改变 Promise 对象状态后,内部触发对应回调函数传参并执行

    image-20230222120815484

  4. 注意:每个 Promise 对象一旦被兑现/拒绝,那就是已敲定了,状态无法再被改变

07.使用 Promise 和 XHR_获取省份列表

  1. Promise 和 XHR 都已经学过基础语法了,我们可以来结合使用一下了

  2. 需求:使用 Promise 和 XHR 请求省份列表数据并展示到页面上

  3. 步骤:

    1. 创建 Promise 对象

    2. 执行 XHR 异步代码,获取省份列表数据

    3. 关联成功或失败回调函数,做后续的处理

      错误情况:用地址错了404演示

  4. 核心代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    /**
    * 目标:使用Promise管理XHR请求省份列表
    * 1. 创建Promise对象
    * 2. 执行XHR异步代码,获取省份列表
    * 3. 关联成功或失败函数,做后续处理
    */
    // 1. 创建Promise对象
    const p = new Promise((resolve, reject) => {
    // 2. 执行XHR异步代码,获取省份列表
    const xhr = new XMLHttpRequest()
    xhr.open('GET', 'http://hmajax.itheima.net/api/province')
    xhr.addEventListener('loadend', () => {
    // xhr如何判断响应成功还是失败的?
    // 2xx开头的都是成功响应状态码
    if (xhr.status >= 200 && xhr.status < 300) {
    resolve(JSON.parse(xhr.response))
    } else {
    reject(new Error(xhr.response))
    }
    })
    xhr.send()
    })

    // 3. 关联成功或失败函数,做后续处理
    p.then(result => {
    console.log(result)
    document.querySelector('.my-p').innerHTML = result.list.join('<br>')
    }).catch(error => {
    // 错误对象要用console.dir详细打印
    console.dir(error)
    // 服务器返回错误提示消息,插入到p标签显示
    document.querySelector('.my-p').innerHTML = error.message
    })

08.封装_简易axios-获取省份列表

  1. 需求:基于 Promise 和 XHR 封装 myAxios 函数,获取省份列表展示到页面

    image-20230222130217597

  2. 核心语法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    function myAxios(config) {
    return new Promise((resolve, reject) => {
    // XHR 请求
    // 调用成功/失败的处理程序
    })
    }

    myAxios({
    url: '目标资源地址'
    }).then(result => {

    }).catch(error => {

    })
  3. 步骤:

    1. 定义 myAxios 函数,接收配置对象,返回 Promise 对象
    2. 发起 XHR 请求,默认请求方法为 GET
    3. 调用成功/失败的处理程序
    4. 使用 myAxios 函数,获取省份列表展示
  4. 核心代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    /**
    * 目标:封装_简易axios函数_获取省份列表
    * 1. 定义myAxios函数,接收配置对象,返回Promise对象
    * 2. 发起XHR请求,默认请求方法为GET
    * 3. 调用成功/失败的处理程序
    * 4. 使用myAxios函数,获取省份列表展示
    */
    // 1. 定义myAxios函数,接收配置对象,返回Promise对象
    function myAxios(config) {
    return new Promise((resolve, reject) => {
    // 2. 发起XHR请求,默认请求方法为GET
    const xhr = new XMLHttpRequest()
    xhr.open(config.method || 'GET', config.url)
    xhr.addEventListener('loadend', () => {
    // 3. 调用成功/失败的处理程序
    if (xhr.status >= 200 && xhr.status < 300) {
    resolve(JSON.parse(xhr.response))
    } else {
    reject(new Error(xhr.response))
    }
    })
    xhr.send()
    })
    }

    // 4. 使用myAxios函数,获取省份列表展示
    myAxios({
    url: 'http://hmajax.itheima.net/api/province'
    }).then(result => {
    console.log(result)
    document.querySelector('.my-p').innerHTML = result.list.join('<br>')
    }).catch(error => {
    console.log(error)
    document.querySelector('.my-p').innerHTML = error.message
    })

09.封装_简易axios-获取地区列表

  1. 需求:在上个封装的建议 axios 函数基础上,修改代码支持传递查询参数功能

  2. 修改步骤:

    1. myAxios 函数调用后,判断 params 选项
    2. 基于 URLSearchParams 转换查询参数字符串
    3. 使用自己封装的 myAxios 函数显示地区列表
  3. 核心代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    function myAxios(config) {
    return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest()
    // 1. 判断有params选项,携带查询参数
    if (config.params) {
    // 2. 使用URLSearchParams转换,并携带到url上
    const paramsObj = new URLSearchParams(config.params)
    const queryString = paramsObj.toString()
    // 把查询参数字符串,拼接在url?后面
    config.url += `?${queryString}`
    }

    xhr.open(config.method || 'GET', config.url)
    xhr.addEventListener('loadend', () => {
    if (xhr.status >= 200 && xhr.status < 300) {
    resolve(JSON.parse(xhr.response))
    } else {
    reject(new Error(xhr.response))
    }
    })
    xhr.send()
    })
    }

    // 3. 使用myAxios函数,获取地区列表
    myAxios({
    url: 'http://hmajax.itheima.net/api/area',
    params: {
    pname: '辽宁省',
    cname: '大连市'
    }
    }).then(result => {
    console.log(result)
    document.querySelector('.my-p').innerHTML = result.list.join('<br>')
    })
作者

步步为营

发布于

2024-05-08

更新于

2025-03-15

许可协议