文章目录标题
- Ajax学习笔记
-
- axios使用
- axios请求拦截器
- axios响应拦截器
- form-serialize插件
- 图片上传
- HTTP协议
- [AJAX原理 - XMLHttpRequest](#AJAX原理 - XMLHttpRequest)
-
- 使用XMLHttpRequest
- [XMLHttpRequest - 查询参数](#XMLHttpRequest - 查询参数)
- [XMLHttpRequest - 数据提交](#XMLHttpRequest - 数据提交)
- 事件循环
- Promise对象
-
- 同步代码和异步代码
- Promise的三种状态
- 通过Promise+XHR模拟axios实现
- [Promise - 链式调用](#Promise - 链式调用)
- [Promise.all 静态方法](#Promise.all 静态方法)
- async函数和await关键字
Ajax学习笔记
定义:Ajax是异步的JavaScript和XML。简单来说就是使用XMLHttpRequest对象与服务器通信。它可以使用JSON、XML、HTML和text文本邓格式发送和接收数据。Ajax最吸引人的就是它的"异步"特性,也就是说它可以在不重新刷新页面的情况下与服务器通信、交换数据或更新页面。
概念:Ajax是浏览器与服务器进行数据通信的技术。
作用:浏览器和服务器之间通信,动态数据交互。
axios使用
axios体验步骤:
- 引用axios库
- 使用axios语法
html
<!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请求拦截器:发起请求之前,出发点配置函数,对请求参数进行额外配置。
语法:
js
axios.interceptors.request.use(function (config) {
// 在发送请求之前做什么
return config
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error)
})
axios响应拦截器
axios响应拦截器:响应回到then/catch之前,触发的拦截函数,对响应的结果统一处理。
语法:
js
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:不获取空值
html
<!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携带图片文件
jsconst fd = new FormmData() fd.append(参数名, 值)
-
提交表单数据到服务器,使用图片url网址
html
<!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.url
document.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事件,接收响应结果
-
发起请求
jsconst xhr = new XMLHttpRequest() xhr.open('请求方法', '请求url网址') xhr.addEventListener('loadend', () => { console.log(xhr.response) })
XMLHttpRequest - 查询参数
定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据。
例子:查询河北省的城市名称。
html
<!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对象
- 生成固定格式查询参数的字符串
js
const paramsobj = new URLSearchParams({
参数名1: 值1,
参数名2: 值2
})
const queryString = paramsobj.toString() // 结果:参数名1=值1&参数名2=值2
XMLHttpRequest - 数据提交
核心:
- 请求头设置Content-Type:application/json
- 请求体携带JSON字符串
js
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单线程(某一时刻只能执行一行代码),为了让耗时代码不阻塞其他代码运行,设计了事件循环。
执行过程
定义:执行代码和收集异步任务的模型,在调用栈空闲,反复调用任务队列里回调函数的执行机制,就叫事件循环。
js
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引擎更近,所以先执行微任务队列里的代码,再执行宏任务队列里的代码。
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
js
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函数内部运作机制
- 能解决回调函数地狱问题
核心代码:
js
// 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函数,获取省份列表展示
核心代码模板:
js
function myAxios (config){
return new Promise((resolve, reject) => {
// XHR请求
// 调用成功/失败的处理程序
})
}
myAxios({
url: '目标资源地址'
}).then(result => {
}).catch(error => {
})
完整实现代码:
html
<!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对象的最终状态和结果
好处:通过链式调用,解决回调函数嵌套问题。
链式调用解决回调函数地狱:省份------城市------地区查询
html
<!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 = pname
return axios({ url: 'http://hmajax.itheima.net/api/city', params: { pname } })
}).then(result => {
const cname = result.data.list[0]
document.querySelector('.b').innerHTML = cname
return 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关键字解决回调函数地狱
html
<!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 = pname
document.querySelector('.b').innerHTML = cname
document.querySelector('.c').innerHTML = areaName
}
getData()
</script>
</body>
</html>
async函数和await关键字的错误捕获
使用try...catch语句标记要尝试捕获的语句块,并指定一个出现异常时抛出的响应。
语法:
js
try {
// 要执行的代码
} catch(error) {
// error接收的是错误信息
// try里代码,如果有错误,直接进入这里执行
}
js
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 = pname
document.querySelector('.b').innerHTML = cname
document.querySelector('.c').innerHTML = areaName
} catch (error) {
console.dir(error)
}
}
getData()