Web前端笔记-10、JS基础-Ajax、Ajax原理、Ajax进阶、事件循环、宏任务和微任务、Promise.all

Ajax

AJAX 是浏览器与服务器进行数据通信的技术

  1. 先使用 axios库,与服务器进行数据通信。基于 XMLHttpRequest 封装、代码简单。Vue、react也是使用axios
  2. 再学习 XMLHttpRequest 对象的使用,了解 AJAX 底层原理

axios

axios().then()

在then回调函数中,第一个参数就是服务端返回的数据

axios({
  url:'http://ajax-api.itheima.net/api/province'
}).then(result =>{
  // console.log(result.data)
  const data = result.data.data
  document.querySelector('div').innerHTML = data.join('<br>')
})

axios返回的数据会被axios进行包装

URL查询参数 params

定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据

http://xxxx.com/xxx/xxx?参数名1=值1&参数名2=值2

语法:使用 axios 提供的 params 选项

axios 在运行时把参数名和值,会拼接到 url?参数名=值

axios({
  url:'',
  params:{
    参数名: 值
  }
}).then(result =>{
  
})

例子:

axios({
  url:'http://ajax-api.itheima.net/api/city',
  params:{
    pname: '河北省'
  }
}).then(result =>{
  const {data: {data}} = result
  document.querySelector('div').innerHTML = data.join('<br>')
})

常用请求方法

请求方法 操作
GET 获取数据
POST 数据提交
PUT 修改数据(全部)
DELETE 删除数据
PATCH 修改数据(部分)

axios请求配置

url:请求的 URL 网址

method:请求的方法,GET可以省略(不区分大小写)

data:提交数据

params:查询参数

<!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>常用请求方法和数据提交</title>
</head>

<body>
  <button class="btn">注册用户</button>
  <script src="./lib/axios.min.js"></script>

  <script>
    document.querySelector('.btn').addEventListener('click', e =>{
      axios({
        url: 'http://hmajax.itheima.net/api/register',
        method: 'POST',
        data: {
          username: 'goodgoods2',
          password: '123456'
        }
      }).then(res => {
        const {data: {data: {id}}} = res
        console.log(`新用户id为${id}`);
      })
    })
  </script>
</body>

</html>

axios错误处理

处理:用更直观的方式,给普通用户展示错误信息

语法:在 then 方法的后面,通过点语法调用catch 方法,传入回调函数并定义形参。

axios({
}).then(res => {
}).catch(error => {

})

HTTP-报文

HTTP 协议:规定了浏览器发送及服务器返回内容的格式

请求报文:浏览器按照 HTTP 协议要求的格式,发送给服务器的内容

  1. 请求行:请求方法,URL,协议
  2. 请求头:以键值对的格式携带的附加信息,比如:Content-Type (标头)
  3. 空行:分隔请求头,空行之后的是发送给服务器的资源
  4. 请求体:发送的资源 (载荷)

响应报文:服务器按照 HTTP 协议要求的格式,返回给浏览器的内容

  1. 响应行(状态行):协议、HTTP 响应状态码、状态信息
  2. 响应头:以键值对的格式携带的附加信息,比如:Content-Type
  3. 空行:分隔响应头,空行之后的是服务器返回的资源
  4. 响应体:返回的资源 (预览、响应)

form-serialize插件

作用:快速收集表单元素的值

https://www.npmjs.com/package/form-serialize

const form = document.querySelector('.example-form')
// serialize(form) 会得到 键=值&键=值 查询参数 
// 键是表单项的name属性值,值是value
var str = serialize(form)
// serialize(form, { hash: true, empty: true }) 会得到对象
// 键同样是表单项的name属性值,值是value
// 不加empty: true,如果表单项没填,得到空对象;加了,是空值
// {} 与 {uname:''}的区别
var obj = serialize(form, { hash: true, empty: true })

表单项一定要有name属性。

16.19案例:问答机器人

综合案例:图书馆

Ajax原理

XMLHttpRequest XHR

axios 内部采用 XMLHttpRequest 与服务器交互

  1. 创建 XMLHttpRequest 对象
  2. 配置请求方法和请求 url 地址 xhr.open
  3. 监听 loadend 事件,接收响应结果 xhr.addEnventListener
  4. 发起请求 xhr. send

如果传请求体。

请求体参数步骤

  1. 设置请求头数据类型 根据接口文档设置
  2. 在send方法中携带参数

Promise

Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值。

好处:

  1. 逻辑更清晰
  2. 了解 axios 函数内部运作机制
  3. 能解决回调函数地狱问题
const p = new Promise((resolve, reject) => {})
  // 执行异步任务-并传递结果
  // 成功调用:resolve(值)触发 then()执行
  // 失败调用:reject(值) 触发 catch()执行
  //接收结果
p.then(result=> {
  // 成功
}).catch(error =>
  // 失败
})

Promise的三种状态

pending 待定状态

成功调用执行resolve 来到 fulfiled 已兑现状态

失败调用执行reject 来到 rejected 已拒绝状态

Ajax进阶

同步代码和异步代码

浏览器是按照我们书写代码的顺序一行一行地执行程序的。浏览器会等待代码的解析和工作,在上一行完成后才会执行下一行。这样做是很有必要的,因为每一行新的代码都是建立在前面代码的基础之上的。这也使得它成为一个同步程序。

异步编程技术使你的程序可以在执行一个可能长期运行的任务的同时继续对其他事件做出反应而不必等待任务完成。与此同时,程序也将在任务完成后显示结果。

同步代码:逐行执行,需原地等待结果后,才继续向下执行。

异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发一个回调函数。

现在学到的异步任务:

  1. 定时器。
  2. 事件。
  3. ajax

回调函数地狱

回调函数嵌套回调函数就是回调地狱。

缺点:可读性差,异常无法获取,耦合性严重,牵一发动全身

Promise链式调用解决回调地狱

Promise链式调用:依靠 then()方法会返回一个新生成的 Promise 对象特性,继续串联下一环任务,直到结束。

细节:then()回调函数中的返回值,会影响新生成的 Promise 对象最终状态和结果。 .then().then()

axios({
  url: 'http://hmajax.itheima.net/api/province',
  method: 'GET'
})
.then(res => {
  document.querySelector('.province').innerHTML = res.data.list[0]
  // return出去 下一层级的 axios(本质是一个Promise对象)
  return axios({
    url: 'http://hmajax.itheima.net/api/city',
    method: 'GET',
    params: {
      pname: res.data.list[0]
    }
  })
})
.then(res => {
  document.querySelector('.city').innerHTML = res.data.list[0]
})

此时,链式调用也是有问题的。
每个then中的回调函数作用域都不同,想使用前面then的变量需要在外设置一个全局变量存储。
同时,虽然解决了回调地狱,但代码变长了。

async和await使用解决回调地狱

async和await都是修饰符,async用来修饰函数,await用来修饰异步任务。

它们是解决链式调用的问题的。

async要加在离await最近的函数前边。

概念:在 async修饰的函数内,使用 await 关键字取代then函数等待获取 Promise对象成功状态的结果值。

解决不了错误状态。

await取代了then,axios请求后返回的结果也就不在then中的回调中拿到,而是await返回了一个结果,使用变量拿到即可。

await会阻止“异步函数内“代码继续执行,原地等待结果

async function render(){
  const {data:{list:plist}} = await axios({url: 'http://hmajax.itheima.net/api/province'})        
  console.log(plist[0])
  const {data:{list:clist}} = await axios({url: 'http://hmajax.itheima.net/api/city', params:{pname: plist[0]}})
  console.log(clist[0])
  const {data:{list:alist}} = await axios({url: 'http://hmajax.itheima.net/api/area', params:{pname: plist[0], cname: clist[0]}})
  console.log(alist[0])
}
render()

捕获错误

在async修饰的函数里使用try...catch(error)...

事件循环 EventLoop

掌握JavaScript 是如何安排和运行代码的

console.log(1)
setTimeout(()=>{
  console.log(2)
},0) // 异步任务会等待同步任务完成
console.log(3)

// 1 3 2

JavaScript 有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。这个模型与其它语言中的模型截然不同,比如C和 Java。

原因:Javascript 单线程(某一刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环模型。

JS单线程,同步任务会放在JS的调用栈中执行,但是异步任务会放在宿主环境即浏览器或node中。(浏览器是多线程的)

  1. JS调用栈,执行同步任务
  2. 宿主环境,不执行JS代码,触发后会把异步任务的回调函数放入任务队列
  3. 任务队列,JS调用栈执行完毕,去任务队列找函数并放入调用栈执行

这就是事件循环

宏任务和微任务

区分JS中的异步代码

E56 之后引入了 Promise 对象,让JS 引擎也可以发起异步任务。

异步任务分为:

宏任务:由宿主环境执行的异步代码

微任务:由JS引擎环境执行的异步代码

宏任务:

JS脚本执行事件(script)

setTimeout/setlnterval

AJAX请求完成事件

用户交互事件等 执行所在环境

微任务:

Promise对象.then()

Promise 本身是同步的,而then和catch回调函数是异步的

则有:调用栈、宿主环境、宏任务队列、微任务队列

先同步任务,然后执行宏任务队列,再执行当前宏任务产生的微任务,再执行下一个宏任务。(整个script也是一个宏任务)

Promise.all静态方法

概念:合并多个 Promise 对象,等待所有同时成功完成(或某一个失败),做后续逻辑(和事务差不多,一个失败都失败,调用合并后的promise的catch)

const p = Promise.all([Promise对象, Promise对象, ...])

p.then p.catch

const arr = []
arr.push(
  axios({url:'http://hmajax.itheima.net/api/weather', params:{city:'110100'}}),
  axios({url:'http://hmajax.itheima.net/api/weather', params:{city:'310100'}}),
  axios({url:'http://hmajax.itheima.net/api/weather', params:{city:'440100'}}),
  axios({url:'http://hmajax.itheima.net/api/weather', params:{city:'440300'}})
)
async function getWeather(){
  try {
    const res = await Promise.all(arr)
    document.querySelector('.weather').innerHTML = res.map(city=>{
      const {data:{data:{area, dateShort, psPm25Level}}} = city
      return `<li>${dateShort}---${area}---${psPm25Level}</li>`
    }).join('')
  } catch (error) {
    console.log(error) 
  }
}
getWeather()
posted @ 2025-05-27 00:33  subeipo  阅读(32)  评论(0)    收藏  举报