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企服之家,中国第一个企服评测及商务社交产业平台。 |