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 来获取到你的相关信息,比如登录密码等。
你有两种解决方式:

异步请求通常不会直接改变欣赏器地点栏中的 URL。这是因为这些请求是独立于欣赏器的传统同步请求(如直接在地点栏输入 URL 或点击链接)发起的。
异步请求的特点:





异步与回调函数

异步操作需要一种机制来关照调用者操作何时完成。而回调函数就是这种关照机制之一。




XMLHttpRequest 对象

Ajax 通过 XMLHttpRequest 对象来实现异步交互,具体的怎么实现的在 Ajax 代码实现中讲述,这里我们先学习 XMLHttpRequest 对象是什么。


xhr,全称为 XMLHttpRequest,用于与服务器交互数据,是 ajax 功能实现所依赖的对象。
当客户端发出请求时,请求数据发送给 XMLHttpRequest 而不是直接发送给服务器。而且请求是异步发送的。
而且,服务器不在将数据直接返回给客户端欣赏器,而是返回给 XMLHttpRequest 对象。
XMLHttpRequest 可以实现客户端与服务器只进行数据层面的交互,而不是视图层面的交互。


五种状态

XMLHttpRequest 对象的五种状态:


三种属性







ajax代码实现

ajax 通过 XMLHttpRequest 对象的 send() 方法来发送异步请求,通过 XMLHttpRequest 对象的onreadystatechange 函数来实现回调。
  1. <html>
  2.     <script>
  3.     function getMessage(){
  4.         // 实例化一个xmlHttpRequest对象
  5.         var request = new XMLHttpRequest();
  6.         
  7.         // 设置xmlHttpRequest对象的回调函数
  8.         /**
  9.         * onreadystatechange 是request对象的一个属性,表示当准备状态发生改变时
  10.         * 准备状态由 readystate 表示
  11.         * 准备状态有 1、2、3、4 四个状态,如下:
  12.         *     0 (UNSENT):请求已创建,但 open() 方法还未被调用。
  13.         *     1 (OPENED):open() 方法已被调用,但 send() 方法还未被调用。
  14.         *     2 (HEADERS_RECEIVED):send() 方法已被调用,响应头部和状态已可获得。
  15.         *     3 (LOADING):响应主体正在加载,即响应内容(如果有的话)正在被接收。
  16.         *     4 (DONE):请求已完成,响应已就绪。
  17.         */
  18.         // request.status 就是状态码
  19.         request.onreadystatechange = function(){
  20.             if(request.readyState == 4 && request.status == 200){
  21.                 // 接收响应结果,处理结果            
  22.                     // eg: 使用request.responseText 接收后端响应回来的响应体中的数据
  23.                         // 使用DOM编程
  24.                     var inputEle = document.getElemenyById("message")
  25.                     inputEle.value = request.responseText;
  26.                     // eg: 把响应信息跳转到别的页面展示,使用BOM编程
  27.                     window.location.href = "www.baidu.com"
  28.             }        
  29.         }
  30.         
  31.         // 设置发送请求的方式和请求的资源路径
  32.         request.open("GET", "/user/checkUsernameUserd?username=zhangsan")
  33.         
  34.         // 发送请求
  35.         request.send()
  36.         
  37.     }
  38.     </script>
  39. <body>
  40.     <input type="text" iod="message">
  41. </body>
  42. </html>
复制代码

ajax的缺点:回调地狱

所谓回调地狱就是回调函数嵌套的太多层了,看的不惬意而已。
即 AJAX 调用是异步的,这意味着它们不会阻塞代码的执行。但是当使用回调函数处置惩罚 AJAX 请求的效果时,假如多个请求依次依赖于前一个请求的效果,每个请求都需要等候前一个请求完成后才气执行,这就形成了嵌套的回调函数,即回调地狱。
  1. var xhr1 = new XMLHttpRequest();
  2. xhr1.open('GET', 'url1', true);
  3. xhr1.onreadystatechange = function() {
  4.   if (xhr1.readyState === 4 && xhr1.status === 200) {
  5.     // 处理第一个请求的结果
  6.     var result1 = xhr.responseText;
  7.     // 根据第一个请求的结果发起第二个请求
  8.     var xhr2 = new XMLHttpRequest();
  9.     xhr2.open('GET', 'url2?param=' + result1, true);
  10.     xhr2.onreadystatechange = function() {
  11.       if (xhr2.readyState === 4 && xhr2.status === 200) {
  12.         // 处理第二个请求的结果
  13.         var result2 = xhr2.responseText;
  14.         // 根据第二个请求的结果发起第三个请求
  15.         var xhr3 = new XMLHttpRequest();
  16.         xhr3.open('GET', 'url3?param=' + result2, true);
  17.         xhr3.onreadystatechange = function() {
  18.           if (xhr3.readyState === 4 && xhr3.status === 200) {
  19.             // 处理第三个请求的结果
  20.             var result3 = xhr3.responseText;
  21.             console.log(result3);
  22.           }
  23.         };
  24.         xhr3.send();
  25.       };
  26.     };
  27.     xhr2.send();
  28.   };
  29. };
  30. 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,该属性有三种状态:

只有异步操作的效果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是 promise 这个名字的由来,它的英语意思就是“答应",表现其他本领无法改变。
PromiseState 的初始值是 pending,而且状态只能改变一次。即promise 对象的状态改变,只有两种大概: 从 Pending 变为 Resolved 和从 Pending 变为 Rejected。只要这两种环境发生,状态就擬固了,不会再变了,不停保持这个效果。

promise 的简单使用

这里为了方便理解,临时不讲 async 以及 await 关键字。
  1. <script>
  2.     let promise = new Promise(function (resolve, reject){
  3.         resolve("hello promise")
  4.         // 该方法表示 Promise 成功完成,并且将字符串 "hello promise" 作为结果
  5.         // 传递给后续的 .then() 方法中的成功处理函数。
  6.         
  7.         // js 也可以像Java一样向外抛异常
  8.         // throw new Eorror(`error message`)   
  9.         // 在这写是用来测试promise2.catch()
  10.     })
  11.    
  12.     let promise2 = promise.then(
  13.         // 等待 promise 对象状态发生改变时才会执行的代码:
  14.         function(value) { // resolve() 的实现代码在这
  15.         
  16.             // promise 的状态由 pending 转换为 resolved 时.会执行的函数
  17.             console.log(value)    // 输出:hello promise
  18.         },
  19.         
  20.         function(value ) {
  21.              // promise 的状态由 pending 转换为 reject 时,会执行的函数
  22.         }
  23.     )
  24.     let promise3 = promise2.catch(
  25.         function() {
  26.             // 当promise状态是reject 或 promise出现异常时 会执行的函数
  27.         }   
  28.     )
  29.     promise3.finally(
  30.         function() {
  31.             // 当promise状态无论是resolved还是reject,都会执行的代码
  32.         }   
  33.     )
  34. </script>
复制代码

promise 封装 ajax

promise 的出现是为了解决 ajax 的回调地狱,那具体是怎样解决的呢?
书接上文,我们在讲 Ajax 回调地狱时举了一个例子,里面有三个回调函数相互嵌套。即

这里就专门针对这个例子来解说 promise 去怎样解决三个回调函数相互嵌套的。
  1. // 创建一个Promise对象
  2. function fetchData() {
  3.     return new Promise((resolve, reject) => {
  4.         var xhr1 = new XMLHttpRequest();
  5.         xhr1.open('GET', 'https://api.example.com/data1', true);
  6.         xhr1.onload = function() {
  7.             if (xhr1.status === 200) {
  8.                 var data1 = JSON.parse(xhr1.responseText);
  9.                 // 请求成功,使用promise的resolve方法返回响应数据
  10.                 resolve(data1);
  11.             } else {
  12.                 // 请求失败,使用promise的reject方法返回错误状态
  13.                 reject(new Error('请求失败'));
  14.             }
  15.         };
  16.         xhr1.onerror = function() {
  17.             // 请求失败,使用promise的reject方法返回错误状态
  18.             reject(new Error('网络错误'));
  19.         };
  20.         xhr1.send();
  21.     })
  22.     .then(data1 => {
  23.         return new Promise((resolve, reject) => {
  24.             var xhr2 = new XMLHttpRequest();
  25.             xhr2.open('GET', 'https://api.example.com/data2?param=' + data1.id, true);
  26.             xhr2.onload = function() {
  27.                 if (xhr2.status === 200) {
  28.                     var data2 = JSON.parse(xhr2.responseText);
  29.                     resolve(data2);
  30.                 } else {
  31.                     reject(new Error('请求失败'));
  32.                 }
  33.             };
  34.             xhr2.onerror = function() {
  35.                 reject(new Error('网络错误'));
  36.             };
  37.             xhr2.send();
  38.         });
  39.     }) // promise.then返回的就是一个promise对象,因此下一行可以再次.then
  40.     .then(data2 => {
  41.         return new Promise((resolve, reject) => {
  42.             var xhr3 = new XMLHttpRequest();
  43.             xhr3.open('GET', 'https://api.example.com/data3?param=' + data2.id, true);
  44.             xhr3.onload = function() {
  45.                 if (xhr3.status === 200) {
  46.                     var data3 = JSON.parse(xhr3.responseText);
  47.                     resolve(data3);
  48.                 } else {
  49.                     reject(new Error('请求失败'));
  50.                 }
  51.             };
  52.             xhr3.onerror = function() {
  53.                 reject(new Error('网络错误'));
  54.             };
  55.             xhr3.send();
  56.         });
  57.     })
  58.     .then(data3 => {
  59.         console.log('所有数据已获取:', data3);
  60.     })
  61.     .catch(error => {
  62.         console.error('请求过程中发生错误:', error);
  63.     });
  64. }
  65. // 调用函数
  66. fetchData();
复制代码
可以看到 promise 接纳 promise对象.then() 的方式来解决嵌套的。实在作用都一样,只是 promise 的方式看起来更惬意而已。

axios

我们可以观察到 promise 封装 ajax 发送网络请求的代码包罗创建XMLHttpRequest对象、ajax发送请求、Ajax的回调函数、promise 的回调函数(promise.then()、promise.catch()、promise.finally)。这属实黑白常的贫苦。
因此人们发明了 axios,即 Axios 就是对 Ajax 的一种简化使用。



axios 的实现

eg:
向后端发送请求,获取土味情话并展示到页面。

  1. <script setup>
  2. import axios from 'axios'
  3. import {reactive} from 'vue'
  4. let message = reactive( {
  5.     "code":1,
  6.     "content":"我这么努力不是为了你,而是因为你"
  7. })
  8. function getLoveMessage() {
  9.     // 使用 axios 发送请求获取土味情话:
  10.     // axios() 函数可以发送各种类型的 HTTP 请求
  11.     // 每个 axios() 请求都返回一个 Promise 对象,
  12.     // 这意味着你可以使用 .then()、.catch() 方法来处理异步结果,或者使用 async/await 语法。
  13.     let promise = axios({   
  14.     // axios 中的参数是一个对象
  15.     // 对象的第一个属性是请求方式
  16.     // 对象的第二个属性是请求地址
  17.     // 对象的第三个属性是请求体
  18.     // 对象的第四个属性是请求参数
  19.         method:"get",
  20.         url:"https://api.uomg.com/api/rand.qinghua?format=json",
  21.         
  22.         // 如果请求方式是 get,则data中的数据会以键值对形式放在url后
  23.         // 如果请求方式 post,则data中的数据会以JSON形式放入请求体
  24.         data:{
  25.             // 这里的数据会放入请求体 前提是请求方式得是 post。
  26.             // 如果是 get,则请求体里什么也不会有。
  27.             
  28.         },
  29.         params:{
  30.             // 无论是post 还是 get,这里的数据都是以键值对方式将数据放
  31.             // 入url后,注意:这里的数据和url需要用?隔开。
  32.             // 在开发者工具=》网络=》标头=》请求标头中可以看到这里定义的数据。
  33.             
  34.         }
  35.     })
  36.    
  37.     promise.then(
  38.         function(response) {
  39.             console.log(response)
  40.             /*
  41.             response就是响应结果对象,其中,
  42.                 data:服务端响应回来的数据
  43.                 status:响应状态码,例如,200
  44.                 statusText:响应状态描述,例如,200对应OK
  45.                 headers:本次响应的所有响应头
  46.                 config:本次请求的配置信息
  47.                 request:本次请求发送时所使用的 XMLHttpRequest 对象
  48.             */
  49.             console.log(response.data.code)
  50.             console.log(response.data.content)
  51.             /*前后端交互使用的是 json 字符串,但是当你使用 Ajax 或
  52.             Axios时,则它们会自动地把JSON字符串转换成 JSON 对象。
  53.             */
  54.         }   
  55.     ).catch{
  56.         function(error) {
  57.             console.log(error)
  58.         }   
  59.     }
  60. }
  61. </script>
  62. <template>
  63.     <div>
  64.         <h1 v-text="message.content"></h1>
  65.         <button @click="getLoveMessage()">变</button>
  66.     </div>
  67. </template>
复制代码

至此我们就讲完了从AJAX到Promise再到Axios的发展之路,希望能对各位朋友理清 AJAX、Promise、Axios之间的关系起到帮助作用。

下面是扩展知识。
上述的 axios 代码还可以继续改进。
改进版1

上述代码中的 getLoveMessage() 中既有 axios 的发送请求,又有 promise.then 和 promist.catch,这就太耦合了。
那我现在把 getLoveMessage 中的 axios 的发送请求功能拆分到 getLoveWords() 中,可以看着更轻快些。
  1. <script setup>
  2. import axios from 'axios'
  3. import {reactive} from 'vue'
  4. let message = reactive( {
  5.     "code":1,
  6.     "content":"我这么努力不是为了你,而是因为你"
  7. })
  8. function getLoveWords() {
  9.    return axios({    // axios 中的参数是一个对象
  10.     method:"get",
  11.     url:"https://api.uomg.com/api/rand.qinghua?format=json",
  12.     data:{},
  13.     params:{}
  14.     })
  15. }
  16. function getLoveMessage() {
  17.     let promise = getLoveWords()
  18.     promise.then(
  19.         function(response) {
  20.             console.log(response)
  21.             console.log(response.data.code)
  22.         }   
  23.     ).catch{}
  24. }
  25. </script>
  26. <template>
  27.     <div>
  28.         <h1 v-text="message.content"></h1>
  29.         <button @click="getLoveMessage()">变</button>
  30.     </div>
  31. </template>
复制代码


改进版2

上述的改进版1中的promise可以使用 async 以及 await 关键字
  1. <script setup>
  2. import axios from 'axios'
  3. import {reactive} from 'vue'
  4. let message = reactive( {
  5.     "code":1,
  6.     "content":"我这么努力不是为了你,而是因为你"
  7. })
  8. function getLoveWords() {
  9.    return axios({    // axios 中的参数是一个对象
  10.     method:"get",
  11.     url:"https://api.uomg.com/api/rand.qinghua?format=json",
  12.     data:{},
  13.     params:{}
  14.     })
  15. }
  16. //function getLoveMessage() {
  17. //    let promise = getLoveWords()
  18. //    promise.then(
  19. //        function(response) {
  20. //            console.log(response)
  21. //            console.log(response.data.code)
  22. //        }   
  23. //    ).catch{}
  24. //}
  25. // 上述代码不就是想要拿到 response 嘛,我们可以这么拿
  26. async function getLoveMessage() {
  27.     let response = await getLoveWords()
  28.     Object.assign(message, response.data)   
  29.     // assign()的作用是将后一个参数的属性赋值给前一个参数的同名属性上
  30. }
  31. </script>
  32. <template>
  33.     <div>
  34.         <h1 v-text="message.content"></h1>
  35.         <button @click="getLoveMessage()">变</button>
  36.     </div>
  37. </template>
复制代码

改进版3

使用解构表达式
  1. <script setup>
  2. import axios from 'axios'
  3. import {reactive} from 'vue'
  4. let message = reactive( {
  5.     "code":1,
  6.     "content":"我这么努力不是为了你,而是因为你"
  7. })
  8. function getLoveWords() {
  9.    return axios({    // axios 中的参数是一个对象
  10.     method:"get",
  11.     url:"https://api.uomg.com/api/rand.qinghua?format=json",
  12.     data:{},
  13.     params:{}
  14.     })
  15. }
  16. //async function getLoveMessage() {
  17. //    let response = await getLoveWords()
  18. //    Object.assign(message, response.data)   
  19. //    // assign()的作用是将后一个参数的属性赋值给前一个参数的同名属性上
  20. //}
  21. // 上述代码不就是想要拿到 response.data 嘛,我们可以使用解构表达式
  22. async function getLoveMessage() {
  23.     let {data} = await getLoveWords()
  24.     Object.assign(message, data)   
  25. }
  26. </script>
  27. <template>
  28.     <div>
  29.         <h1 v-text="message.content"></h1>
  30.         <button @click="getLoveMessage()">变</button>
  31.     </div>
  32. </template>
复制代码


改进版4

直接使用 axios.get 发送请求
  1. <script setup>
  2. import axios from 'axios'
  3. import {reactive} from 'vue'
  4. let message = reactive( {
  5.     "code":1,
  6.     "content":"我这么努力不是为了你,而是因为你"
  7. })
  8. function getLoveWords() {
  9. //   return axios({    // axios 中的参数是一个对象
  10. //    method:"get",
  11. //    url:"https://api.uomg.com/api/rand.qinghua?format=json",
  12. //    data:{},
  13. //    params:{}
  14. //    })
  15. // 上述代码可以简写为
  16.     return axios.get("https://api.uomg.com/api/rand.qinghua?format=json")
  17. }
  18. async function getLoveMessage() {
  19.     let {data} = await getLoveWords()
  20.     Object.assign(message, data)   
  21. }
  22. </script>
  23. <template>
  24.     <div>
  25.         <h1 v-text="message.content"></h1>
  26.         <button @click="getLoveMessage()">变</button>
  27.     </div>
  28. </template>
复制代码
此中,
axios.get() 会自动发送 get 请求,并返回一个 promise 对象。此中的参数有以下几种情势:

eg:



改进版4平行版

除了可以直接使用 axios.get 发送请求,我们也可以使用 axios.post 发送请求
  1. <script setup>
  2. import axios from 'axios'
  3. import {reactive} from 'vue'
  4. let message = reactive( {
  5.     "code":1,
  6.     "content":"我这么努力不是为了你,而是因为你"
  7. })
  8. function getLoveWords() {
  9.     return axios.post("https://api.uomg.com/api/rand.qinghua?format=json")
  10. }
  11. async function getLoveMessage() {
  12.     let {data} = await getLoveWords()
  13.     Object.assign(message, data)   
  14. }
  15. </script>
  16. <template>
  17.     <div>
  18.         <h1 v-text="message.content"></h1>
  19.         <button @click="getLoveMessage()">变</button>
  20.     </div>
  21. </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