目录
[AJAX原理 - XMLHttpRequest](#AJAX原理 - XMLHttpRequest)
[Promise - 三种状态](#Promise - 三种状态)
什么是AJAX?
概念:AJAX是浏览器与服务器进行数据通信的技术。
定义:AJAX是异步的JavaScript和XML(Asynchronous JavaScript And XML)。简单点说,就是使用XMLHttpRequest对象与服务器通信。它可以使用JSON,XML,HTML和text文本等格式发送和接收数据。AJAX最吸引人的就是它的"异步"特性,也就是说它可以在不重新刷新页面的情况下与服务器通信,交换数据,或更新页面。
如何使用AJAX?
语法
- 引入axios.js:https://cdn.jsdelivr.net/npm/axios/dist/axios/min.js
- 使用axios函数
- 传入配置对象
- 再用**.then**回调函数接收结果,并做后续处理
接下来让我们通过代码演示看看ajax的作用吧,代码、需求及效果图如下:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ajax</title>
</head>
<body>
<!--
axios库地址:https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js
省份数据地址:http://hmajax.itheima.net/api/province
目标:使用axios库,获取省份列表数据,展示到页面上
-->
<!-- 渲染 -->
<p class="my-p"></p>
<!-- 1.引入axios库 -->
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<!-- 2.使用axios函数 -->
<script>
axios({
url:'http://hmajax.itheima.net/api/province'
}).then(result => {
// 打印返回结果
console.log(result)
// 打印省份列表
console.log(result.data.list)
// 打印省份
console.log(result.data.list.join('<br>'))
// 插入页面
document.querySelector('.my-p').innerHTML = result.data.list.join('<br>')
})
</script>
</body>
</html>
可以看到,通过axios函数我们可以从url中获取数据资源,并进行处理,那么url是什么意思呢?接下来我们进行详细的了解。
url详解
URL的概念
Internet上的每一个网页都具有一个唯一的名称标识,通常称之为URL(Uniform Resource Locator, 统一资源定位器)。
它是www的统一资源定位标志,简单地说URL就是web地址,俗称"网址"。
URL的组成
URL由三部分组成:资源类型、存放资源的主机域名、资源文件名
也可认为由4部分组成:协议、主机、端口、路径。(很多时候端口都是隐藏的)
还可以认为由7部分组成:协议,域名,端口,虚拟目录,文件名,锚,参数
URL的一般语法格式:(带方括号[]的为可选项):protocol :// hostname[:port] / path / [;parameters][?query]#fragment
**案例:**https://www.baidu.com协议:https
**域名(IP):**www.baidu.com
端口(port):443
资源路径:当没有资源路径时,可以默认是 / ,在各个网站通常有默认的路径如index.html
URL查询参数
定义:浏览器提供给服务器的额外信息,让服务器返回浏览器想要的数据
语法:http://xxxx.com/xxx/xxx**?**参数名1=值1**\&**参数名2=值2
示例:假如前面的案例,我要获取河北省下辖市的信息,就可以写为:
axios
现在开始,我们对axios进行全面的了解和使用。
axios-查询参数
语法:使用axios提供的params选项
注意:axios在运行时把参数名和值,会拼接到url**?参数名=值**
javascript
axios({
url:'目标资源地址'
params:{
参数名:值
}
}).then(result=>{
//对服务器返回的数据做后续处理
})
那么让我们来使用查询参数查询一下云南省下辖市吧:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>查询参数</title>
</head>
<body>
<p></p>
<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(result => {
console.log(result.data.list)
document.querySelector('p').innerHTML = result.data.list.join('<br>')
})
</script>
</body>
</html>
渲染图如上所示,可以看到我们的确拿到了对应的数据,那么此时我们就完成了对查询参数的学习了。
axios-请求配置
常用请求方法
现在我们已经可以从服务器拿到对应的数据了,那么接下来我们来学习一下然后对服务器数据做其他的相关操作:
请求方法:对服务器资源,要执行的操作
|--------|----------|
| 请求方法 | 操作 |
| GET | 获取数据 |
| POST | 提交数据 |
| PUT | 修改数据(全部) |
| DELETE | 删除数据 |
| PATCH | 修改数据(部分) |
那么接下来我们就看看axios请求配置该如何操作吧:
-
url:请求的URL网址
-
method :请求的方法,GET可以省略(不区分大小写)
-
data:提交数据
axios({
url: '目标资源地址',
method: '请求方法',
data: {
参数名:值
}
}).then((result)=>{
// 对服务器返回的数据做后续处理
})
接下来我们使用POST完成一个案例吧:
<!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="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/*
注册用户:http://hmajax.itheima.net/api/register
请求方法:POST
参数名:
username:用户名(中英文和数字组成,最少8位)
password:密码 (最少6位)
目标:点击按钮,通过axios提交用户和密码,完成注册
*/
document.querySelector('.btn').addEventListener('click', () => {
axios({
url: 'http://hmajax.itheima.net/api/register',
method: 'POST',
data: {
username: 'qingwan666',
password: 'qingwan666'
}
}).then(result => {
console.log(result);
})
})
</script>
</body>
</html>
打开网页-点击按钮后效果图->
再次点击按钮效果图->
axios-错误处理
通过刚才的案例,我们发现第二次点击按钮之后会输出错误信息,因为我们第二次点击注册按钮,原本的账号已经被我们注册过了,在服务器中已经不是唯一的了,所以给我们返回了一个报错信息,提示账号被占用,那么我们如何处理这种情况呢?
语法 :在then 方法的后面,通过点语法调用catch 方法,传入回调函数 并定义形参
axios({
//请求选项
}).then(result=>{
//处理数据
}).catch(error=>{
//处理错误
})
接下来我们继续使用刚刚的案例来完成错误处理的代码,需求:重复注册时通过弹窗提示用户错误原因
html
<!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>axios错误处理</title>
</head>
<body>
<button class="btn">注册用户</button>
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
/*
注册用户: http://hmajax.itheima.net/api/register
请求方法: POST
参数名:
username: 用户名 (中英文和数字组成, 最少8位)
password: 密码 (最少6位)
目标: 点击按钮, 通过axios提交用户和密码, 完成注册
需求: 使用axios错误处理语法, 拿到报错信息, 弹框反馈给用户
*/
document.querySelector('.btn').addEventListener('click', () => {
axios({
url: 'http://hmajax.itheima.net/api/register',
method: 'post',
data: {
username: 'qingwan666',
password: 'qingwan666'
}
}).then(result => {
// 成功
console.log(result)
}).catch(error => {
// 失败
// 处理错误信息
console.log(error)
console.log(error.response.data.message)
alert(error.response.data.message)
})
})
</script>
</body>
</html>
点击按钮重复注册后->
这里就可以看到,重复注册时,浏览器已经能够通过弹窗提示用户了。
HTTP协议
那么关于Post和Get......,我们要如何在浏览器中看到对应的信息呢?它们的原理是什么呢?接下来我们要开始针对HTTP进行学习。
HTTP协议:规定了浏览器发送及服务器返回内容的格式
HTTP协议-请求报文
请求报文:浏览器按照HTTP协议要求的格式 ,发送给服务器的内容
请求报文的组成:
- 请求行:请求方法,URL,协议
- 请求头:以键值对的格式携带的附加信息,比如:Content-Type
- 空行:分割请求头,空行之后的是发送给服务器的资源
- 请求体:发送的资源
接下来我们继续用前面的案例,来看看HTTP的请求报文:
网络->左侧选择名称->标头->原始:这里就可看到请求行与请求头了
再点击负载:即可查看请求体
HTTP协议-响应报文
响应报文:服务器按照HTTP协议要求的格式 ,返回给浏览器的内容
响应报文的组成:
- 响应行(状态行):协议、HTTP响应状态码、状态信息
- 响应头:以键值对的格式携带的附加信息,比如:Content-Type
- 空行:分割响应头,空行之后的是发送给服务器的资源
- 响应体:返回的资源
HTTP响应状态码:用来表明请求是否成功完成
以下是各个状态码说明。例如:404(服务器找不到资源)
|-----|-------|
| 状态码 | 说明 |
| 1xx | 信息 |
| 2xx | 成功 |
| 3xx | 重定向消息 |
| 4xx | 客户端错误 |
| 5xx | 服务端错误 |
查看响应报文的方式与请求报文大致相同,只需要将请求标头换为响应标头,负载换为响应即可
接口文档
接口文档:描述接口的文章(后端工程师提供)
接口:使用AJAX和服务器通讯时,使用的URL,请求方法,以及参数
举例:下图为登录接口文档
这里给了我们请求方法、URL,以及需要的参数,那么我们用代码来写一下登入功能:
html
<!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="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
<script>
document.querySelector('.btn').addEventListener('click', () => {
// 用户登录
axios({
url: 'http://hmajax.itheima.net/api/login',
method: 'post',
data: {
username: 'qingwan666',
password: 'qingwan666'
}
})
})
</script>
</body>
</html>
点击登录按钮->
以上就是接口文档的使用教程啦,接下来我们进入下一步的学习。
AJAX原理
AJAX原理 - XMLHttpRequest
定义:XMLHttpRequest(XHR)对象用于与服务器交互,通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL,获取数据。这允许网页在不影响用户操作的情况下,更新页面的局部内容。XMLHttpRequest在AJAX变成中被大量使用。
关系:axios内部采用XMLHttpRequest与服务器交互
步骤:
-
创建XMLHttpRequest对象
-
配置请求方法 和请求url地址
-
监听loadend事件,接收响应结果
-
发起请求
const xhr = new XMLHttpRequest()
xhr.open('请求方法', '请求url网址')
xhr.addEventListener('loadend', () => {
//响应结果
console.log(xhr.response)
})
//发送请求
xhr.send()
我们继续用前面获取地区的案例来演示一下原生XML如何使用:
html
<!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>
网页效果图->
接下来我们看看原生XML查询参数的使用案例:
html
<!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="city-p"></p>
<script>
/**
* 目标:使用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()
</script>
</body>
</html>
再看看如何提交数据:
html
<!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>
<button class="reg-btn">注册用户</button>
<script>
/**
* 目标:使用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)
})
</script>
</body>
</html>
学习原生XML只是为了了解axios的原理,帮助我们更加方便的使用它,继续开始下一步的学习
Promise
由于AJAX是异步请求,对于有些场景,如果请求失败,那么需要如何操作呢?
这时候我们就需要Promise来帮助我们管理
定义:Promise对象用于表示一个异步操作的最终完成(或失败)及其结果值。
我们再了解下学习Promise有什么好处:
- 逻辑更清晰
- 了解axios函数内部运作机制
- 能解决回调函数地狱问题
html
// 1.创建Promise对象
const p = new Promise((resolve, reject) => {
//2.执行异步任务-并传递结果
//成功调用:resolve(值) 触发then()执行
//失败调用:reject(值) 触发catch()执行
})
// 3.接收结果
p.then(result => {
//成功
}).catch(error => {
//失败
})
让我们用代码看看Promise吧:
html
<!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>认识Promise</title>
</head>
<body>
<script>
/**
* 目标:使用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)
})
</script>
</body>
</html>
Promise - 三种状态
作用:了解Promise对象如何关联 的处理函数,以及代码执行顺序
- new Promise() 此时的Promise状态:待定
- resolve() 此时的Promise状态:已兑现(.then(回调函数))
- reject() 此时的Promise状态:已拒绝(.catch(回调函数))
待定(pending):初始状态,既没有被兑现,也没有被拒绝
已兑现(fulfilled):意味着,操作成功完成
已拒绝(rejected):意味着,操作失败
注意:Promise对象一旦被兑现/拒绝,就无法改变状态了
AJAX封装
现在我们已经学习了XML和Promise,也就是axios内部最核心的两个技术我们都已经掌握,那么现在我们来像axios函数一样进行一个调用。
需求:基于Promise + XHR封装myAxios函数,获取省份列表展示
步骤:
- 定义myAxios函数,接收配置兑现 ,返回Promise对象
- 发起XHR请求,默认请求方法为GET
- 调用成功/失败的处理程序
- 使用myAxios函数,获取省份列表展示
代码实现:
html
<!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>封装_简易axios函数_获取省份列表</title>
</head>
<body>
<p class="my-p"></p>
<script>
/**
* 目标:封装_简易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
})
</script>
</body>
</html>
网页部分效果图->
再看看axios查询参数的封装案例吧:
html
<!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>封装_简易axios函数_获取地区列表</title>
</head>
<body>
<p class="my-p"></p>
<script>
/**
* 目标:封装_简易axios函数_获取地区列表
* 1. 判断有params选项,携带查询参数
* 2. 使用URLSearchParams转换,并携带到url上
* 3. 使用myAxios函数,获取地区列表
*/
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>')
})
</script>
</body>
</html>
最后看看提交数据的封装,我们也就完成对AJAX的学习了:
html
<!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>封装_简易axios函数_注册用户</title>
</head>
<body>
<button class="reg-btn">注册用户</button>
<script>
/**
* 目标:封装_简易axios函数_注册用户
* 1. 判断有data选项,携带请求体
* 2. 转换数据类型,在send中发送
* 3. 使用myAxios函数,完成注册用户
*/
function myAxios(config) {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest()
if (config.params) {
const paramsObj = new URLSearchParams(config.params)
const queryString = paramsObj.toString()
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))
}
})
// 1. 判断有data选项,携带请求体
if (config.data) {
// 2. 转换数据类型,在send中发送
const jsonStr = JSON.stringify(config.data)
xhr.setRequestHeader('Content-Type', 'application/json')
xhr.send(jsonStr)
} else {
// 如果没有请求体数据,正常的发起请求
xhr.send()
}
})
}
document.querySelector('.reg-btn').addEventListener('click', () => {
// 3. 使用myAxios函数,完成注册用户
myAxios({
url: 'http://hmajax.itheima.net/api/register',
method: 'POST',
data: {
username: 'itheima999',
password: '666666'
}
}).then(result => {
console.log(result)
}).catch(error => {
console.dir(error)
})
})
</script>
</body>
</html>