ToB企服应用市场:ToB评测及商务社交产业平台
标题:
从AJAX到Promise再到Axios
[打印本页]
作者:
美食家大橙子
时间:
2025-1-8 04:39
标题:
从AJAX到Promise再到Axios
ajax
异步交互
首先我先讲讲为什么需要 ajax,因为我们需要异步交互,那我们为什么需要异步交互呢?
我以为异步交互有两个长处:
1. 相比于同步交互,异步交互可以更大程度地提高服务器的使用服从,不至于让服务器有空闲的时候。
拓展一个知识点:js是单线程语言,欣赏器只分配给js一个主线程,用来执行任务。但是js却是可以实现异步,这得益于欣赏器帮助js实现的。详细内容可以看JavaScript的单线程和异步 - 知乎
2. 异步保护 url 信息
假如你使用 get 方法向后端发送 http 请求,则请求所附带的参数会跟在 url 的 ?后,此时假如你使用的是公共的 wifi,则别人可以获取你的 url,进而就有大概根据你的 url 来获取到你的相关信息,比如登录密码等。
你有两种解决方式:
一种是使用 post 请求方式,这种方式会把请求的参数信息放到请求体中,而请求体一样平常是颠末加密的。
一种是使用异步交互,异步交互不会改变 url,即
异步请求通常不会直接改变欣赏器地点栏中的 URL。这是因为这些请求是独立于欣赏器的传统同步请求(如直接在地点栏输入 URL 或点击链接)发起的。
异步请求的特点:
独立于欣赏器导航:异步请求不会使欣赏器加载新页面或重新加载当前页面。它们在背景与服务器交换数据,而不影响当前页面的状态或URL。
不改变 URL:这些请求不会改变欣赏器地点栏中的 URL,因为它们不触发欣赏器的导航行为。用户在地点栏中看到的 URL 保持不变。
更新页面内容:只管异步请求不直接改变 URL,但它们可以用于更新页面的某部分内容。例如,获取最新的用户评论或股票代价,并在不刷新整个页面的环境下更新这些信息。
异步与回调函数
异步操作需要一种机制来关照调用者操作何时完成。而回调函数就是这种关照机制之一。
XMLHttpRequest 对象
Ajax 通过 XMLHttpRequest 对象来实现异步交互,具体的怎么实现的在 Ajax 代码实现中讲述,这里我们先学习 XMLHttpRequest 对象是什么。
xhr,全称为 XMLHttpRequest,用于与服务器交互数据,是 ajax 功能实现所依赖的对象。
当客户端发出请求时,请求数据发送给 XMLHttpRequest 而不是直接发送给服务器。而且请求是异步发送的。
而且,服务器不在将数据直接返回给客户端欣赏器,而是返回给 XMLHttpRequest 对象。
XMLHttpRequest 可以实现客户端与服务器只进行数据层面的交互,而不是视图层面的交互。
五种状态
XMLHttpRequest 对象的五种状态:
0(未初始化)还没有调用send()方法
1(载入)已调用send()方法,已创建服务器连接
2(载入完成)send()方法执行完成,已经吸收到全部相应内容
3(交互)正在剖析相应内容
4(完成)相应内容剖析完成,可以在客户端调用了
三种属性
ajax代码实现
ajax 通过 XMLHttpRequest 对象的 send() 方法来发送异步请求,通过 XMLHttpRequest 对象的onreadystatechange 函数来实现回调。
<html>
<script>
function getMessage(){
// 实例化一个xmlHttpRequest对象
var request = new XMLHttpRequest();
// 设置xmlHttpRequest对象的回调函数
/**
* onreadystatechange 是request对象的一个属性,表示当准备状态发生改变时
* 准备状态由 readystate 表示
* 准备状态有 1、2、3、4 四个状态,如下:
* 0 (UNSENT):请求已创建,但 open() 方法还未被调用。
* 1 (OPENED):open() 方法已被调用,但 send() 方法还未被调用。
* 2 (HEADERS_RECEIVED):send() 方法已被调用,响应头部和状态已可获得。
* 3 (LOADING):响应主体正在加载,即响应内容(如果有的话)正在被接收。
* 4 (DONE):请求已完成,响应已就绪。
*/
// request.status 就是状态码
request.onreadystatechange = function(){
if(request.readyState == 4 && request.status == 200){
// 接收响应结果,处理结果
// eg: 使用request.responseText 接收后端响应回来的响应体中的数据
// 使用DOM编程
var inputEle = document.getElemenyById("message")
inputEle.value = request.responseText;
// eg: 把响应信息跳转到别的页面展示,使用BOM编程
window.location.href = "www.baidu.com"
}
}
// 设置发送请求的方式和请求的资源路径
request.open("GET", "/user/checkUsernameUserd?username=zhangsan")
// 发送请求
request.send()
}
</script>
<body>
<input type="text" iod="message">
</body>
</html>
复制代码
ajax的缺点:回调地狱
所谓回调地狱就是回调函数嵌套的太多层了,看的不惬意而已。
即 AJAX 调用是异步的,这意味着它们不会阻塞代码的执行。但是当使用回调函数处置惩罚 AJAX 请求的效果时,假如多个请求依次依赖于前一个请求的效果,每个请求都需要等候前一个请求完成后才气执行,这就形成了嵌套的回调函数,即回调地狱。
var xhr1 = new XMLHttpRequest();
xhr1.open('GET', 'url1', true);
xhr1.onreadystatechange = function() {
if (xhr1.readyState === 4 && xhr1.status === 200) {
// 处理第一个请求的结果
var result1 = xhr.responseText;
// 根据第一个请求的结果发起第二个请求
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', 'url2?param=' + result1, true);
xhr2.onreadystatechange = function() {
if (xhr2.readyState === 4 && xhr2.status === 200) {
// 处理第二个请求的结果
var result2 = xhr2.responseText;
// 根据第二个请求的结果发起第三个请求
var xhr3 = new XMLHttpRequest();
xhr3.open('GET', 'url3?param=' + result2, true);
xhr3.onreadystatechange = function() {
if (xhr3.readyState === 4 && xhr3.status === 200) {
// 处理第三个请求的结果
var result3 = xhr3.responseText;
console.log(result3);
}
};
xhr3.send();
};
};
xhr2.send();
};
};
xhr.send();
复制代码
上述存在三个回调函数,分别是 xhr1.onreadystatechange = function() {}、xhr2.onreadystatechange = function() {}以及xhr3.onreadystatechange = function() {}。
此中,
xhr3.onreadystatechange = function() {} 嵌套在 xhr2.onreadystatechange = function() {} 中。
xhr2.onreadystatechange = function() {} 嵌套在 xhr1.onreadystatechange = function() {} 中。
看的不惬意,于是便出现了 promise。
promise
Promise 本质是个构造函数,其作用就是将 new Promist() 内的普通的函数转换成回调函数,而且返回一个 Promise 对象。我们可以从这个 Promise 对象身上获取异步操作的效果,即 promist 对象的状态。接着我们通过这个状态来执行相应的回调函数。
PromiseState(状态)
promise 对象代表一个异步操作,其有一个属性 PromiseState,该属性有三种状态:
Pending(未决定的初始状态)
Resolved(已完成,又称 Fulfilled)
Rejected(被拒绝)
只有异步操作的效果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 promise 这个名字的由来,它的英语意思就是“答应",表现其他本领无法改变。
PromiseState 的初始值是 pending,而且状态只能改变一次。即promise 对象的状态改变,只有两种大概: 从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种环境发生,状态就擬固了,不会再变了,不停保持这个效果。
promise 的简单使用
这里为了方便理解,临时不讲 async 以及 await 关键字。
<script>
let promise = new Promise(function (resolve, reject){
resolve("hello promise")
// 该方法表示 Promise 成功完成,并且将字符串 "hello promise" 作为结果
// 传递给后续的 .then() 方法中的成功处理函数。
// js 也可以像Java一样向外抛异常
// throw new Eorror(`error message`)
// 在这写是用来测试promise2.catch()
})
let promise2 = promise.then(
// 等待 promise 对象状态发生改变时才会执行的代码:
function(value) { // resolve() 的实现代码在这
// promise 的状态由 pending 转换为 resolved 时.会执行的函数
console.log(value) // 输出:hello promise
},
function(value ) {
// promise 的状态由 pending 转换为 reject 时,会执行的函数
}
)
let promise3 = promise2.catch(
function() {
// 当promise状态是reject 或 promise出现异常时 会执行的函数
}
)
promise3.finally(
function() {
// 当promise状态无论是resolved还是reject,都会执行的代码
}
)
</script>
复制代码
promise 封装 ajax
promise 的出现是为了解决 ajax 的回调地狱,那具体是怎样解决的呢?
书接上文,我们在讲 Ajax 回调地狱时举了一个例子,里面有三个回调函数相互嵌套。即
xhr3.onreadystatechange = function() {} 嵌套在 xhr2.onreadystatechange = function() {} 中。
xhr2.onreadystatechange = function() {} 嵌套在 xhr1.onreadystatechange = function() {} 中。
这里就专门针对这个例子来解说 promise 去怎样解决三个回调函数相互嵌套的。
// 创建一个Promise对象
function fetchData() {
return new Promise((resolve, reject) => {
var xhr1 = new XMLHttpRequest();
xhr1.open('GET', 'https://api.example.com/data1', true);
xhr1.onload = function() {
if (xhr1.status === 200) {
var data1 = JSON.parse(xhr1.responseText);
// 请求成功,使用promise的resolve方法返回响应数据
resolve(data1);
} else {
// 请求失败,使用promise的reject方法返回错误状态
reject(new Error('请求失败'));
}
};
xhr1.onerror = function() {
// 请求失败,使用promise的reject方法返回错误状态
reject(new Error('网络错误'));
};
xhr1.send();
})
.then(data1 => {
return new Promise((resolve, reject) => {
var xhr2 = new XMLHttpRequest();
xhr2.open('GET', 'https://api.example.com/data2?param=' + data1.id, true);
xhr2.onload = function() {
if (xhr2.status === 200) {
var data2 = JSON.parse(xhr2.responseText);
resolve(data2);
} else {
reject(new Error('请求失败'));
}
};
xhr2.onerror = function() {
reject(new Error('网络错误'));
};
xhr2.send();
});
}) // promise.then返回的就是一个promise对象,因此下一行可以再次.then
.then(data2 => {
return new Promise((resolve, reject) => {
var xhr3 = new XMLHttpRequest();
xhr3.open('GET', 'https://api.example.com/data3?param=' + data2.id, true);
xhr3.onload = function() {
if (xhr3.status === 200) {
var data3 = JSON.parse(xhr3.responseText);
resolve(data3);
} else {
reject(new Error('请求失败'));
}
};
xhr3.onerror = function() {
reject(new Error('网络错误'));
};
xhr3.send();
});
})
.then(data3 => {
console.log('所有数据已获取:', data3);
})
.catch(error => {
console.error('请求过程中发生错误:', error);
});
}
// 调用函数
fetchData();
复制代码
可以看到 promise 接纳 promise对象.then() 的方式来解决嵌套的。实在作用都一样,只是 promise 的方式看起来更惬意而已。
axios
我们可以观察到 promise 封装 ajax 发送网络请求的代码包罗创建XMLHttpRequest对象、ajax发送请求、Ajax的回调函数、promise 的回调函数(promise.then()、promise.catch()、promise.finally)。这属实黑白常的贫苦。
因此人们发明了 axios,即 Axios 就是对 Ajax 的一种简化使用。
axios 的实现
eg:
向后端发送请求,获取土味情话并展示到页面。
<script setup>
import axios from 'axios'
import {reactive} from 'vue'
let message = reactive( {
"code":1,
"content":"我这么努力不是为了你,而是因为你"
})
function getLoveMessage() {
// 使用 axios 发送请求获取土味情话:
// axios() 函数可以发送各种类型的 HTTP 请求
// 每个 axios() 请求都返回一个 Promise 对象,
// 这意味着你可以使用 .then()、.catch() 方法来处理异步结果,或者使用 async/await 语法。
let promise = axios({
// axios 中的参数是一个对象
// 对象的第一个属性是请求方式
// 对象的第二个属性是请求地址
// 对象的第三个属性是请求体
// 对象的第四个属性是请求参数
method:"get",
url:"https://api.uomg.com/api/rand.qinghua?format=json",
// 如果请求方式是 get,则data中的数据会以键值对形式放在url后
// 如果请求方式 post,则data中的数据会以JSON形式放入请求体
data:{
// 这里的数据会放入请求体 前提是请求方式得是 post。
// 如果是 get,则请求体里什么也不会有。
},
params:{
// 无论是post 还是 get,这里的数据都是以键值对方式将数据放
// 入url后,注意:这里的数据和url需要用?隔开。
// 在开发者工具=》网络=》标头=》请求标头中可以看到这里定义的数据。
}
})
promise.then(
function(response) {
console.log(response)
/*
response就是响应结果对象,其中,
data:服务端响应回来的数据
status:响应状态码,例如,200
statusText:响应状态描述,例如,200对应OK
headers:本次响应的所有响应头
config:本次请求的配置信息
request:本次请求发送时所使用的 XMLHttpRequest 对象
*/
console.log(response.data.code)
console.log(response.data.content)
/*前后端交互使用的是 json 字符串,但是当你使用 Ajax 或
Axios时,则它们会自动地把JSON字符串转换成 JSON 对象。
*/
}
).catch{
function(error) {
console.log(error)
}
}
}
</script>
<template>
<div>
<h1 v-text="message.content"></h1>
<button @click="getLoveMessage()">变</button>
</div>
</template>
复制代码
至此我们就讲完了从AJAX到Promise再到Axios的发展之路,希望能对各位朋友理清 AJAX、Promise、Axios之间的关系起到帮助作用。
下面是扩展知识。
上述的 axios 代码还可以继续改进。
改进版1
上述代码中的 getLoveMessage() 中既有 axios 的发送请求,又有 promise.then 和 promist.catch,这就太耦合了。
那我现在把 getLoveMessage 中的 axios 的发送请求功能拆分到 getLoveWords() 中,可以看着更轻快些。
<script setup>
import axios from 'axios'
import {reactive} from 'vue'
let message = reactive( {
"code":1,
"content":"我这么努力不是为了你,而是因为你"
})
function getLoveWords() {
return axios({ // axios 中的参数是一个对象
method:"get",
url:"https://api.uomg.com/api/rand.qinghua?format=json",
data:{},
params:{}
})
}
function getLoveMessage() {
let promise = getLoveWords()
promise.then(
function(response) {
console.log(response)
console.log(response.data.code)
}
).catch{}
}
</script>
<template>
<div>
<h1 v-text="message.content"></h1>
<button @click="getLoveMessage()">变</button>
</div>
</template>
复制代码
改进版2
上述的改进版1中的promise可以使用 async 以及 await 关键字
<script setup>
import axios from 'axios'
import {reactive} from 'vue'
let message = reactive( {
"code":1,
"content":"我这么努力不是为了你,而是因为你"
})
function getLoveWords() {
return axios({ // axios 中的参数是一个对象
method:"get",
url:"https://api.uomg.com/api/rand.qinghua?format=json",
data:{},
params:{}
})
}
//function getLoveMessage() {
// let promise = getLoveWords()
// promise.then(
// function(response) {
// console.log(response)
// console.log(response.data.code)
// }
// ).catch{}
//}
// 上述代码不就是想要拿到 response 嘛,我们可以这么拿
async function getLoveMessage() {
let response = await getLoveWords()
Object.assign(message, response.data)
// assign()的作用是将后一个参数的属性赋值给前一个参数的同名属性上
}
</script>
<template>
<div>
<h1 v-text="message.content"></h1>
<button @click="getLoveMessage()">变</button>
</div>
</template>
复制代码
改进版3
使用解构表达式
<script setup>
import axios from 'axios'
import {reactive} from 'vue'
let message = reactive( {
"code":1,
"content":"我这么努力不是为了你,而是因为你"
})
function getLoveWords() {
return axios({ // axios 中的参数是一个对象
method:"get",
url:"https://api.uomg.com/api/rand.qinghua?format=json",
data:{},
params:{}
})
}
//async function getLoveMessage() {
// let response = await getLoveWords()
// Object.assign(message, response.data)
// // assign()的作用是将后一个参数的属性赋值给前一个参数的同名属性上
//}
// 上述代码不就是想要拿到 response.data 嘛,我们可以使用解构表达式
async function getLoveMessage() {
let {data} = await getLoveWords()
Object.assign(message, data)
}
</script>
<template>
<div>
<h1 v-text="message.content"></h1>
<button @click="getLoveMessage()">变</button>
</div>
</template>
复制代码
改进版4
直接使用 axios.get 发送请求
<script setup>
import axios from 'axios'
import {reactive} from 'vue'
let message = reactive( {
"code":1,
"content":"我这么努力不是为了你,而是因为你"
})
function getLoveWords() {
// return axios({ // axios 中的参数是一个对象
// method:"get",
// url:"https://api.uomg.com/api/rand.qinghua?format=json",
// data:{},
// params:{}
// })
// 上述代码可以简写为
return axios.get("https://api.uomg.com/api/rand.qinghua?format=json")
}
async function getLoveMessage() {
let {data} = await getLoveWords()
Object.assign(message, data)
}
</script>
<template>
<div>
<h1 v-text="message.content"></h1>
<button @click="getLoveMessage()">变</button>
</div>
</template>
复制代码
此中,
axios.get() 会自动发送 get 请求,并返回一个 promise 对象。此中的参数有以下几种情势:
eg:
改进版4平行版
除了可以直接使用 axios.get 发送请求,我们也可以使用 axios.post 发送请求
<script setup>
import axios from 'axios'
import {reactive} from 'vue'
let message = reactive( {
"code":1,
"content":"我这么努力不是为了你,而是因为你"
})
function getLoveWords() {
return axios.post("https://api.uomg.com/api/rand.qinghua?format=json")
}
async function getLoveMessage() {
let {data} = await getLoveWords()
Object.assign(message, data)
}
</script>
<template>
<div>
<h1 v-text="message.content"></h1>
<button @click="getLoveMessage()">变</button>
</div>
</template>
复制代码
此中,
axios.post() 会自动发送 post 请求,并返回一个 promise 对象。此中的参数有以下几种情势:
axios.post(url,{要放入请求体中的 JSON 串}, {请求的其他信息})
eg:
此中,
params 中的数据照样会放到 url 的?后。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/)
Powered by Discuz! X3.4