AJAX
1、AJAX定义与axios使用
定义: AJAX(Asynchronous Javascript And XML),即异步的JavaScript和XML,是浏览器与服务器进行数据通信的技术。
axios示例:
<body>
<div class="province-list"></div>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
axios({
url: "http://hmajax.itheima.net/api/province"
}).then(result=>{
console.log(result.data.list.join("<br>"));
document.querySelector(".province-list").innerHTML = result.data.list.join("<br>")
})
</script>
</body>
2、URL
2.1 URL简介
定义:URL(Uniform Resource Locator),称为统一资源定位符或网址。
URL示例:http://www.bilibili.com/v/douga/
示例 | 名称 | 作用 |
---|---|---|
http:// | 协议 | 规定浏览器和服务器之间传输数据的格式 |
www.bilibili.com/ | 域名 | 标记服务器在互联网中的位置(确定要访问的服务器) |
v/douga/ | 资源路径 | 标记资源在服务器上的具体位置 |
2.2 URL查询参数
定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据
语法:http://xxxx.com/xxx/xxx?参数1=值1&参数2=值2
查询参数示例:
<body>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
axios({
url:"http://hmajax.itheima.net/api/city",
params:{ // 查询参数写在此处
pname : '湖南省',
}
}).then(res =>{
console.log(res.data.list);
})
</script>
</body>
2.3 常用请求方法
请求方法:对服务器的资源,要采取的操作
请求方法 | 操作 |
---|---|
GET | 获取数据(默认方式,不区分大小写) |
POST | 提交数据 |
PUT | 修改数据(全部) |
DELETE | 删除数据 |
PATCH | 修改数据(部分) |
POST用于注册示例:
<body>
<button class="btn">注册</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
document.querySelector('.btn').addEventListener('click', () =>{
axios({
url : "http://hmajax.itheima.net/api/register",
method : 'post',
data : {
username : 'wqwe1234_',
password : '1234556'
}
}).then(res => {
console.log(res);
})
})
</script>
</body>
3、axios错误处理
使用关键字catch捕获
<body>
<button class="btn">注册</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
document.querySelector('.btn').addEventListener('click', () =>{
axios({
url : "http://hmajax.itheima.net/api/register",
method : 'post',
data : {
username : 'wqwe12322_',
password : '1234556'
}
}).then(res => {
console.log(res);
}).catch(error=>{ // 使用catch捕获异常
console.log(error);
alert(error.response.data.message)
})
})
</script>
</body>
4、HTTP协议
HTTP协议规定了浏览器发送及服务器返回内容的格式
4.1 请求报文
请求报文: 浏览器发送给服务器的内容
组成:
名称 | 示例 | 作用 |
---|---|---|
请求行 | POST /api/register HTTP/1.1 | 请求方式、请求地址、协议 |
请求头 | Accept: application/json, text/plain, */* Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 Connection: keep-alive Content-Length: 46 Content-Type: application/json Host: hmajax.itheima.net Origin: null User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) | 以键值对的格式携带的附加信息,如Content-Type |
请求体 | {“username”:“wqwe12322_”,“password”:“1234556”} | 请求的信息 |
通过谷歌浏览器网络面板查看请求报文
错误排查:通过请求报文排查错误原因,并修复
4.2 响应报文
**响应报文:**服务器按照HTTP协议要求的格式,返回给浏览器的内容
组成:
名称 | 示例 | 作用 |
---|---|---|
响应行 | HTTP/1.1 400 Bad Request | 协议、HTTP协议响应状态码、状态信息 |
响应头 | Date: Thu, 12 Oct 2023 12:06:55 GMT Content-Type: application/json; charset=utf-8 Content-Length: 54 Connection: keep-alive Set-Cookie: acw_tc=2f624a51d;path=/;HttpOnly;Max-Age=1800 Server: nginx Vary: Origin Access-Control-Allow-Origin: null Access-Control-Allow-Credentials: true Accept-Ranges: bytes x-frame-options: SAMEORIGIN x-xss-protection: 1; mode=block x-content-type-options: nosniffv x-download-options: noopen x-readtime: 9 | 以键值对的格式携带的附加信息,如Content-Type |
空行 | 分隔响应头,空行之后是返回给浏览器的资源 | |
响应体 | {“code”:10005,“message”:“账号被占用”,“data”:null} | 返回的资源 |
HTTP协议响应状态码
状态码 | 说明 |
---|---|
1XX | 信息 |
2XX | 成功 |
3XX | 重定向消息 |
4XX | 客户端错误 |
5XX | 服务端错误 |
4.3 接口文档
接口文档:描述接口的文章
接口:使用AJAX和服务器通讯时,使用的URL、请求方法、参数
5、form-serialize收集表单信息
语法:data = serialize**(form**, {hash:true, empty:true})。 使用时,要给表单添加。
参数 | 取值 | 解释 |
---|---|---|
form | 要获取数据的表单 | |
hash | true、false | true:返回JS对象 false:查询字符串 |
empty | true、false | 是否获取空值 |
示例:
<body>
<form class="infor" action="javascript:;">
<span>name:</span>
<input type="text" name="username"> <!-- 使用时,要给表单添加 -->
<span>password:</span>
<input type="passsword" name="password">
<button>提交</button>
</form>
<script src="./lib/form-serialize.js"></script>
<script>
document.querySelector('button').addEventListener('click',()=>{
const form = document.querySelector('.infor')
const data = serialize(form, {hash:true, empty:true})
console.log(data)
})
</script>
</body>
6、bootstrap弹窗使用
官网示例:
<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>Bootstrap 弹框</title>
<!-- 引入bootstrap.css -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<button type="button" class="btn btn-primary change-btn" data-bs-toggle="modal" data-bs-target=".box">编辑姓名</button>
<div class="modal box" tabindex="-1">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">请输入姓名</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<form action="javascript:;">
<span>姓名:</span>
<input type="text" class="username">
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
<button type="button" class="btn btn-save btn-primary">保存</button>
</div>
</div>
</div>
</div>
<!-- 引入bootstrap.js -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script>
<script>
let box = document.querySelector('.box')
let mybox = new bootstrap.Modal(box)
document.querySelector('.change-btn').addEventListener('click', ()=>{
mybox.show()
})
document.querySelector('.box .btn-save').addEventListener('click', ()=>{
const username = document.querySelector('.box .username').value
console.log(username)
mybox.hide()
})
</script>
</body>
</html>
使用步骤:
1、引入官方CSS和JS
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.min.js"></script>
2、CSS控制弹窗的显示和关闭
<!-- 显示:给控制显示弹窗的按钮添加两个自定义属性 data-bs-toggle="modal" data-bs-target=".box" -->
<button type="button" class="btn btn-primary change-btn" data-bs-toggle="modal" data-bs-target=".box">编辑姓名</button>
<!-- 关闭:给控制关闭弹窗的按钮添加自定义属性 data-bs-dismiss="modal"-->
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
3、通过JS控制弹窗的出现和关闭
let box = document.querySelector('.box')
let mybox = new bootstrap.Modal(box)
mybox.show() // 显示
mybox.hide() // 关闭
7、XMLHttpRequest对象使用
7.1 XMLHttpRequest基本使用
XMLHttpRequest对象用于与服务器交互,是AJAX的基本原理;也是axios的内部实现原理。
使用步骤:
- 创建XMLHttpRequest对象
- 调用open方法,配置请求方法和URL
- 监听loadend事件,接收响应结果
- 调用send方法,发起请求
<!--省份渲染 -->
<body>
<div>
<ul class="provience">
<li></li>
</ul>
</div>
<script>
const xhr = new XMLHttpRequest() // 1、创建XMLHttpRequest对象
xhr.open('GET','https://hmajax.itheima.net/api/province') // /2、配置请求方法和URL,
xhr.addEventListener('loadend',res => { // 2、监听loadend事件,接收响应结果
const data = JSON.parse(xhr.response) // 返回位JASON字符串,需要转为对象
const str_data = data.list.map(ele => { return `<li>${ele}</li>`})
document.querySelector('.provience').innerHTML = str_data.join(' ')
})
xhr.send() // 4、发起请求
</script>
</body>
7.2 XMLHttpRequest查询参数
<body>
<div>
<ul class="city">
<li></li>
</ul>
</div>
<script>
const xhr = new XMLHttpRequest()
xhr.open('GET',"https://hmajax.itheima.net/api/city?pname=湖南省") // ?后为携带的查询参数
xhr.addEventListener('loadend', () => {
const data = JSON.parse(xhr.response)
const str_data = data.list.map(item => { return `<li>${item}</li>`})
document.querySelector('.city').innerHTML = str_data.join('')
})
xhr.send()
</script>
</body>
7.3 URLSearchParams使用
作用: 将JS对象转换为URL查询参数
const city_infor = {
pname:'贵州省',
cname:'贵阳市'
}
const param = new URLSearchParams(city_infor)
const string_param = param.toString()
8、Promise
Promise对象用于表示一个异步操作最终完成(或失败)及其结果值。
语法:
// 创建promise对象
const p = new Promise((resolve, reject) => {
// 执行异步任务,并且传递结果
// 成功调用:resolve()触发then()执行
// 失败调用:reject()触发catch()执行
})
// 接收结果
p.then(res => {
// 成功
}).catch(error => {
// 失败
})
8.1 实现axios函数
function myAxios(config)
{
return new Promise((resolve,reject) => {
const xhr = new XMLHttpRequest()
if(config.params)
{
const param = new URLSearchParams(config.params)
const str_param = param.toString()
config.url += `?${str_param}`
}
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))
}
})
if(config.data)
{
xhr.setRequestHeader('Content-Type','application/json')
const str = JSON.stringify(config.data)
xhr.send(str)
}
else{
xhr.send()
}
})
}
8.2 Promise.all静态方法
概念:合并多个Promise对象,等待所有对象同时完成(或某一个失败),然后执行后序逻辑
<script>
const p = Promise.all([Promise对象1, Promise对象2,,....])
p.then(res => {
// 所有Promise对象都获取信息成功
}).catch(error => {
// 某个Promise对象获取信息失败
})
</script>
9、同步代码&异步代码、回调函数
9.1 同步异步&异步代码
同步代码:逐行执行,原地等待结果后,才继续向下执行
异步代码:调用后耗时,不阻塞代码执行,将来完成后触发回调函数
JS中的异步代码:setTimeout/setInterval、事件、AJAX
9.2 回调函数地狱
定义:在回调函数内一直向下嵌套回调函数
// 示例
<body>
<form action="javascript:;">
省份: <select>
<option value="" class="provience"></option>
</select>
城市: <select>
<option value="" class="city"></option>
</select>
地区: <select>
<option value="" class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
axios({url : 'https://hmajax.itheima.net/api/province'}).then(res1 =>{ // 回调函数地域
const pname = res1.data.list[0]
document.querySelector('.provience').innerHTML = pname
axios({url : 'https://hmajax.itheima.net/api/city',params : {pname}}).then(res2 => {
const cname = res2.data.list[0]
document.querySelector('.city').innerHTML = cname
axios({url : 'https://hmajax.itheima.net/api/area', params : {pname, cname}}).then(res3 => {
const area = res3.data.list[0]
document.querySelector('.area').innerHTML = area
})
})
})
</script>
</body>
问题:
- 可读性差
- 异常难以捕获
- 耦合性严重
解决方法:
- promise链式调用
使用then函数返回新的Promise对象特性,一直串联下去
then回调函数中,return的值会传给then函数新生成的Promise对象
// 示例
<body>
<form action="javascript:;">
省份: <select>
<option value="" class="provience"></option>
</select>
城市: <select>
<option value="" class="city"></option>
</select>
地区: <select>
<option value="" class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
let pname = ''
axios({url : 'https://hmajax.itheima.net/api/province'}).then(res1 =>{
pname = res1.data.list[0]
document.querySelector('.provience').innerHTML = pname
return axios({url : 'https://hmajax.itheima.net/api/city',params : {pname}}).then(res2 => {
const cname = res2.data.list[0]
document.querySelector('.city').innerHTML = cname
return axios({url : 'https://hmajax.itheima.net/api/area', params : {pname, cname}}).then(res3 => {
const area = res3.data.list[0]
document.querySelector('.area').innerHTML = area
})
})
}).catch(error => {
console.log(error);
})
</script>
</body>
- 使用async和await
<body>
<form action="javascript:;">
省份: <select>
<option value="" class="provience"></option>
</select>
城市: <select>
<option value="" class="city"></option>
</select>
地区: <select>
<option value="" class="area"></option>
</select>
</form>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
async function getData()
{
try{
const p_obj = await axios({url : 'https://hmajax.itheima.net/api/province'})
const pname = p_obj.data.list[0]
const c_obj = await axios({url : 'https://hmajax.itheima.net/api/city',params : {pname}})
const cname = c_obj.data.list[0]
const a_obj = await axios({url : 'https://hmajax.itheima.net/api/area1', params : {pname, cname}})
const area = a_obj.data.list[0]
document.querySelector('.provience').innerHTML = pname
document.querySelector('.city').innerHTML = cname
document.querySelector('.area').innerHTML = area
}catch(error){
console.dir(error.response);
}
}
getData()
</script>
</body>
10、事件循环(EventLoop)
事件循环: 执行代码和收集异步任务,在调用栈空闲时,反复调用队列里的回调函数执行机制
事件循环作用:JavaScript是单线程的,为了不阻塞JS引擎,设计了事件循环用于处理异步任务
JS代码执行过程:
- 执行同步代码,遇到异步代码交给宿主浏览器环境执行
- 异步有了结果后,把回调函数放入任务队列排队
- 当调用栈空闲后,反复调用任务队列里的回调函数
10.1 宏任务与微任务
宏任务:由浏览器环境执行的异步代码
微任务:由JS引擎环境执行的异步代码
任务(代码) | 执行所在环境 |
---|---|
JS脚本执行事件(script) | 浏览器 |
setTimeout/setInterval | 浏览器 |
AJAX请求完成事件 | 浏览器 |
用户交互事件 | 浏览器 |
Promise对象.then() | JS引擎 |
同时有宏任务和微任务在队列时,先执行微任务(清空微任务队列)再执行宏任务。