Ajax学习笔记
文章目录标题
- Ajax学习笔记
- axios使用
- axios请求拦截器
- axios响应拦截器
- 优化axios响应结果
- form-serialize插件
- 图片上传
- HTTP协议
- 请求报文
- 相应报文
- 接口文档
- AJAX原理 - XMLHttpRequest
- 使用XMLHttpRequest
- XMLHttpRequest - 查询参数
- 查询字符串对象
- XMLHttpRequest - 数据提交
- 事件循环
- 执行过程
- 宏任务和微任务
- Promise对象
- 同步代码和异步代码
- 回调函数地狱
- Promise的三种状态
- 通过Promise+XHR模拟axios实现
- Promise - 链式调用
- 链式调用解决回调函数地狱:省份——城市——地区查询
- Promise.all 静态方法
- async函数和await关键字
- 使用async函数和await关键字解决回调函数地狱
- async函数和await关键字的错误捕获
Ajax学习笔记
定义:Ajax是异步的JavaScript和XML。简单来说就是使用XMLHttpRequest对象与服务器通信。它可以使用JSON、XML、HTML和text文本邓格式发送和接收数据。Ajax最吸引人的就是它的“异步”特性,也就是说它可以在不重新刷新页面的情况下与服务器通信、交换数据或更新页面。
概念:Ajax是浏览器与服务器进行数据通信的技术。
作用:浏览器和服务器之间通信,动态数据交互。
axios使用
axios体验步骤:
- 引用axios库
- 使用axios语法
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><p class="my-p"></p><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>axios({url: 'https://hmajax.itheima.net/api/province'}).then(result => {//console.log(result.data.list.join(`<br>`));document.querySelector('.my-p').innerHTML = result.data.list.join(`<br>`)})</script>
</body></html>
axios请求拦截器
axios请求拦截器:发起请求之前,出发点配置函数,对请求参数进行额外配置。
语法:
axios.interceptors.request.use(function (config) {// 在发送请求之前做什么return config
}, function (error) {// 对请求错误做些什么return Promise.reject(error)
})
axios响应拦截器
axios响应拦截器:响应回到then/catch之前,触发的拦截函数,对响应的结果统一处理。
语法:
axios.interceptors.response.use(function (response) {// 2xx范围内的状态码都会触发该函数// 对响应数据做些什么return response
}, function (error) {// 超出2xx范围的状态码都会触发该函数// 对响应错误做点什么。return Promise.reject(error)
})
优化axios响应结果
目标:axios直接接收服务器返回的响应结果。
form-serialize插件
作用:快速收集表单元素的值。
语法:serialize(form, { hash: true, empty: true })
- form:获取的表单
- hash:设置获取数据结构
- true:JS对象
- false:查询字符串
- empty:设置是否获取空值
- true:获取空值,使数据结构和标签结构一致
- false:不获取空值
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><form action="javascript:;"><input type="text" name="username"><br><input type="text" name="password"><br><input type="button" class="btn" value="提交"></form><script src="../form-serialize.js"></script><script>document.querySelector('.btn').addEventListener('click', () => {const form = document.querySelector('form')const data = serialize(form, { hash: true, empty: true })console.log(data);})</script>
</body></html>
图片上传
使用步骤:
-
获取图片文件对象
-
使用FormData携带图片文件
const fd = new FormmData() fd.append(参数名, 值)
-
提交表单数据到服务器,使用图片url网址
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><input type="file" class="upload"><img src="" alt=""><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>document.querySelector('.upload').addEventListener('change', e => {console.log(e.target.files[0]);const fd = new FormData()fd.append('img', e.target.files[0])axios({url: 'http://hmajax.itheima.net/api/uploadimg',method: 'post',data: fd}).then(result => {const imgurl = result.data.data.urldocument.querySelector('img').src = imgurl})})</script>
</body></html>
HTTP协议
HTTM协议:规定了浏览器发送及服务器返回内容的格式。
请求报文
请求报文:浏览器按照HTTP协议要求的格式,发送给服务器的内容。
组成部分:
- 请求行:请求方法,URL,协议
- 请求头:以键值对的格式携带的附加信息,比如Content-Type
- 空行:分隔请求头,空行之后的是发送给服务器的资源
- 请求体:发送的资源
相应报文
响应报文:服务器按照HTTP协议要求的格式,返回给浏览器的内容。
组成部分:
-
响应行(状态行):协议、HTTP响应状态码、状态信息
-
HTTP响应状态码:用来表明请求释放成功完成
-
状态码 说明 1xx 信息 2xx 成功 3xx 重定向信息 4xx 客户端错误 5xx 服务端错误 -
比如:404(服务器找不到资源)
-
-
响应头:以键值对的格式携带的附加信息,比如Content-Type
-
空行:分隔响应头,空行之后是服务器返回的资源
-
响应体:返回的资源
接口文档
接口文档:描述接口的文章。
接口:使用AJAX和服务器通讯时,使用的URL、请求方法以及参数。
AJAX原理 - XMLHttpRequest
定义:XMLHttpRequest(XHG)对象用于与服务器交互。通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL,获取数据。这允许网页在不影响用户操作的情况下,更新网页的局部内容。
关系:axios内部采用XMLHttpRequest与服务器交互
使用XMLHttpRequest
使用步骤:
-
创建XMLHttpRequest对象
-
配置请求方法和请求url地址
-
监听loadend事件,接收响应结果
-
发起请求
const xhr = new XMLHttpRequest()xhr.open('请求方法', '请求url网址')xhr.addEventListener('loadend', () => {console.log(xhr.response)})
XMLHttpRequest - 查询参数
定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据。
例子:查询河北省的城市名称。
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div></div><script>const xhr = new XMLHttpRequest()xhr.open('get', 'https://hmajax.itheima.net/api/city?pname=河北省')xhr.addEventListener('loadend', () => {console.log(xhr.response);// 将字符串转成对象const data = JSON.parse(xhr.response) // 字符串转对象document.querySelector('div').innerHTML = data.list.join('<br>')})xhr.send()</script>
</body></html>
查询字符串对象
使用步骤:
- 创建URLSearchParams对象
- 生成固定格式查询参数的字符串
const paramsobj = new URLSearchParams({参数名1: 值1,参数名2: 值2})const queryString = paramsobj.toString() // 结果:参数名1=值1&参数名2=值2
XMLHttpRequest - 数据提交
核心:
- 请求头设置Content-Type:application/json
- 请求体携带JSON字符串
const xhr = new XMLHttpRequest()xhr.open('请求方法', '请求url网址')xhr.addEventListener('loadend', () => {console.log(xhr.response);})// 告诉服务器,传递的内容类型,是JSON字符串xhr.setRequestHeader('Content-Type', 'application/json')// 准备数据并转成JSON字符串const user = { username: 'itheima007', password: '7654321' }const userStr = JSON.stringify(user)xhr.send(userStr) // 发送请求体数据
事件循环
概念:JavaScript有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。
原因:JavaScript单线程(某一时刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环。
执行过程
定义:执行代码和收集异步任务的模型,在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫事件循环。
console.log(1);setTimeout(() => {console.log(2);}, 2000)console.log(3);setTimeout(() => {console.log(4);}, 0)console.log(5);// 打印顺序:1 3 5 4 2
宏任务和微任务
ES6之后引入了Promise对象,让JS引擎也可以发起异步任务。
异步任务分为:
- 宏任务:由浏览器环境执行的异步代码
- 微任务:由JS引擎环境执行的异步代码
任务(代码) | 执行所在环境 |
---|---|
JS脚本执行事件(script) | 浏览器 |
setTimeout/setInterval | 浏览器 |
AJAX请求完成事件 | 浏览器 |
用户交互完成事件 | 浏览器 |
Promise对象.then() | JS引擎 |
Promise本身是同步的,而then和catch回调函数是异步的。
因为微任务队列离JS引擎更近,所以先执行微任务队列里的代码,再执行宏任务队列里的代码。
console.log(1);setTimeout(() => {console.log(2);})const p = new Promise((resolve, reject) => {console.log(3);resolve(4)})p.then(result => {console.log(result);})console.log(5);// 打印顺序:1 3 5 4 2
console.log(1)setTimeout(() => {console.log(2)const p = new Promise(resolve => resolve(3))p.then(result => console.log(result))}, 0)const p = new Promise(resolve => {setTimeout(() => {console.log(4)}, 0)resolve(5)})p.then(result => console.log(result))const p2 = new Promise(resolve => resolve(6))p2.then(result => console.log(result))console.log(7)// 1 7 5 6 2 3 4
Promise对象
定义:Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值。
好处:
- 使逻辑更清晰
- 了解axios函数内部运作机制
- 能解决回调函数地狱问题
核心代码:
// 1.创建promise对象const p = new Promise((resolve, reject) => {// 2.执行异步任务并传递结果// 成功调用:resolve(值) 触发then()执行// 失败调用:reject(值) 触发catch()执行})// 3.接收结果p.then(result => {// 成功}).catch(error => {// 失败})
同步代码和异步代码
同步代码:逐步执行,需要原地等待结果后,才继续往下执行。
异步代码:调用后耗时,不阻塞代码继续执行(不必原地等待),在将来完成后触发一个回调函数。
JS中的异步代码:
- setTimeout / setInterval
- 事件
- AJAX
异步代码通过回调函数接受结果。
回调函数地狱
概念:在回调函数中嵌套回调函数,一直嵌套下去就形成了回调函数地狱。
缺点:可读性差,异常无法捕获,耦合性严重,牵一发动全身。
Promise的三种状态
作用:了解Promise对象如何关联的处理函数,以及代码执行顺序。
概念:一个Promise对象,必定处于以下三种状态之中:
- 待定(pending):初始状态,既没有被兑现,也没有被拒绝
- 已兑现(fulfilled):操作成功完成
- 已拒绝(rejected):操作失败
注意:
- promise对象一旦被兑现/拒绝,就是已敲定了,状态无法再被改变。
- new promise()里的回调函数会立即执行
通过Promise+XHR模拟axios实现
需求:基于Promise+XHR封装myAxios函数,获取省份列表展示
步骤:
- 定义myAxios函数,接收配置对象,返回Promise对象
- 发起XHR请求,默认请求方法为get
- 调用成功/失败的处理程序
- 使用myAxios函数,获取省份列表展示
核心代码模板:
function myAxios (config){return new Promise((resolve, reject) => {// XHR请求// 调用成功/失败的处理程序})}myAxios({url: '目标资源地址'}).then(result => {}).catch(error => {})
完整实现代码:
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><p></p><script>function myAxios(config) {return new Promise((resolve, reject) => {const xhr = new XMLHttpRequest()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()})}myAxios({url: 'https://hmajax.itheima.net/api/province'}).then(result => {console.log(result);document.querySelector('p').innerHTML = result.list.join('<br>')}).catch(error => {console.log(error);document.querySelector('p').innerHTML = error.message})</script>
</body></html>
Promise - 链式调用
概念:依靠then()方法会返回一个新生成的Promise对象特性,继续串联下一环任务,直到结束。
细节:then()回调函数中的返回值,会影响新生成的Promise对象的最终状态和结果
好处:通过链式调用,解决回调函数嵌套问题。
链式调用解决回调函数地狱:省份——城市——地区查询
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div class="a"></div><div class="b"></div><div class="c"></div><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>let pname = ''const p = axios({ url: 'http://hmajax.itheima.net/api/province' }).then(result => {pname = result.data.list[0]document.querySelector('.a').innerHTML = pnamereturn axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })}).then(result => {const cname = result.data.list[0]document.querySelector('.b').innerHTML = cnamereturn axios({ url: 'http://hmajax.itheima.net/api/area', params: { pname, cname } })}).then(result => {const areaName = result.data.list[0]document.querySelector('.c').innerHTML = areaName})</script>
</body></html>
Promise.all 静态方法
概念:合并多个Promise对象,等待所有同时成功完成(或某一个失败),做后续逻辑。
需求:当需要同一时间显示多个请求时,就需要把多请求合并。
语法:const p = Promise.all([对象1, 对象2, ...])
async函数和await关键字
定义:asyn和await关键字让我们可以用一种更简洁的方式写出基于Promise的异步行为,而无需刻意地链式调用Promise。
概念:在async函数内,使用await关键字取代then函数,等待获取Promise对象成功状态的结果值。
使用async函数和await关键字解决回调函数地狱
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><div class="a"></div><div class="b"></div><div class="c"></div><script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script><script>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 areaName = aobj.data.list[0]document.querySelector('.a').innerHTML = pnamedocument.querySelector('.b').innerHTML = cnamedocument.querySelector('.c').innerHTML = areaName}getData()</script>
</body></html>
async函数和await关键字的错误捕获
使用try…catch语句标记要尝试捕获的语句块,并指定一个出现异常时抛出的响应。
语法:
try {// 要执行的代码
} catch(error) {// error接收的是错误信息// try里代码,如果有错误,直接进入这里执行
}
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/area', params: { pname, cname } })const areaName = aobj.data.list[0]document.querySelector('.a').innerHTML = pnamedocument.querySelector('.b').innerHTML = cnamedocument.querySelector('.c').innerHTML = areaName} catch (error) {console.dir(error)}}getData()