• 封装Ajax--解决地狱回调问题


    一、回调函数封装Ajax

    (一)普通Ajax请求数据

      后端index.js注册网址并写入数据

    1. var router=require("./router.js")
    2. router.get("/news",function(req,res){
    3. var obj={data:[{title:"新闻1",content:"内容1",id:1},
    4. {title:"新闻2",content:"内容2",id:2},
    5. {title:"新闻3",content:"内容3",id:3}
    6. ]}
    7. var str=JSON.stringify(obj)
    8. res.setHeader("content-Type","text/json;charset=utf8")
    9. res.end(str)
    10. })
    11. router.get("/author",function(req,res){
    12. var obj=[{name:"lily",id:1},
    13. {name:"lucy",id:2},
    14. {name:"jack",id:3}
    15. ]
    16. var str=JSON.stringify(obj)
    17. res.setHeader("content-Type","text/json;charset=utf8")
    18. res.end(str)
    19. })

       前端index.html文件请求news的数据:

    1. <button onclick="fn()">Ajax请求数据button>
    2. <script>
    3. function fn(){
    4. var xhr=new XMLHttpRequest()||new ActiveXObject("Microsoft.XMLHTTP")
    5. xhr.open("GET","/news",true) //请求news的数据
    6. xhr.send()
    7. xhr.onreadystatechange=function(){
    8. if(xhr.readyState==4&&xhr.status==200){
    9. console.log(xhr.responseText)
    10. //根据业务需求处理数据
    11. }
    12. }
    13. }
    14. script>

     前端index.html文件请求author的数据:

    1. <button onclick="fn()">Ajax请求数据button>
    2. <script>
    3. function fn(){
    4. var xhr=new XMLHttpRequest()||new ActiveXObject("Microsoft.XMLHTTP")
    5. xhr.open("GET","/author",true) //请求author的数据
    6. xhr.send()
    7. xhr.onreadystatechange=function(){
    8. if(xhr.readyState==4&&xhr.status==200){
    9. console.log(xhr.responseText)
    10. //根据业务需求处理数据
    11. }
    12. }
    13. }
    14. script>

    请求 news 和 author 这两个网址接口的数据就要发送两次Ajax网络请求才能获得不同的数据,若想请求其他接口的数据就要写更多的网络请求代码。这样就很麻烦,因为每次请求的代码是一样的,只是请求的网址和请求到的数据的处理方式不同。所以,可以根据这个特点设计一个网络请求工具来简化代码,使网络请求更灵活。

    (二)网络请求工具请求数据

      tool(url,cb):

      tool函数就是一个简单的封装了ajax网络请求的工具

      tool函数先用ajax请求传入的第一个参数url对应网址

      当请求到并返回数据时  就把数据传给cb函数使用(调用cb)去执行业务

      此时能满足不同的网址请求和各样的业务,实现代码复用

    示例:

    当fn点击事件发生后,tool工具函数就会请求网址得到数据,再将数据传给业务(回调)函数,开始执行业务

      前端index.html文件请求数据:(author.html同理)

    1. <script src="./tool.js">script>
    2. <button onclick="fn()">工具函数请求数据button>
    3. <script>
    4. function fn(){
    5. tool("/news",function(str){
    6. //将网络请求到的数据用于业务中(写页面)
    7. var obj = JSON.parse(str)
    8. for (let i = 0; i < obj.data.length; i++) {
    9. console.log(obj.data[i],1111)
    10. let box = document.createElement("div")
    11. box.className = "box"
    12. box.innerHTML = `${obj.data[i].title}---${obj.data[i].content}`
    13. document.body.appendChild(box)
    14. }
    15. })
    16. }
    17. script>

       工具文件 tool.js

    1. function tool(url, cb) {
    2. //封装Ajax网络请求代码
    3. var xhr = new XMLHttpRequest() || new ActiveXObject("Microsoft.XMLHTTP")
    4. xhr.open("GET", url, true)
    5. xhr.send()
    6. xhr.onreadystatechange = function() {
    7. if (xhr.readyState == 4 && xhr.status == 200) {
    8. //将请求到的数据传给cb回调函数执行业务
    9. cb(xhr.responseText)
    10. }
    11. }
    12. }

      后端index.js注册网址并写入数据

    1. var router=require("./router.js")
    2. router.get("/news",function(req,res){
    3. var obj={data:[{title:"新闻1",content:"内容1",id:1},
    4. {title:"新闻2",content:"内容2",id:2},
    5. {title:"新闻3",content:"内容3",id:3}
    6. ]}
    7. var str=JSON.stringify(obj)
    8. res.setHeader("content-Type","text/json;charset=utf8")
    9. res.end(str)
    10. })
    11. router.get("/author",function(req,res){
    12. var obj=[{name:"lily",id:1},
    13. {name:"lucy",id:2},
    14. {name:"jack",id:3}
    15. ]
    16. var str=JSON.stringify(obj)
    17. res.setHeader("content-Type","text/json;charset=utf8")
    18. res.end(str)
    19. })

     请求结果:

     二、jquery封装Ajax

    用回调函数封装Ajax需要自己设计tool函数,而通过jquery只需要一个引入一个jquery框架就可以实现以上效果

     准备工作:引入jquery标签 

    修改以上代码:

    1、弃用tool.js

    2、将    替换为

    3、将tool函数名 替换为 $.get

     示例:

     前端author.html文件请求数据:(index.html同理)

    1. <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/jquery/2.2.4/jquery.js">script>
    2. <button onclick="fn()">用jQuery请求数据button>
    3. <script>
    4. function fn() {
    5. $.get("/author", function(res) {
    6. console.log(res)
    7. })
    8. }
    9. script>

    请求结果:

     三、promise封装Ajax

    (一)回调地狱

    • 回调地狱指的是异步任务中回调函数的层层嵌套
    • 随着嵌套的层数增加,代码的可读性和维护性变差
    • 常见的回调函数如在ajax请求回调、setTimeout、事件回调等中,以函数作为参数进行调用

     示例:

      ajax请求回调地狱

    1. <h1>promise封装ajaxh1>
    2. <script>
    3. function fn() {
    4. $.get("/ajax1", (res1) => {
    5. console.log(res1, JSON.parse(res1), 1)
    6. $.get("/ajax2", (res2) => {
    7. console.log(res2, JSON.parse(res2), 2)
    8. $.get("/ajax3", (res3) => {
    9. console.log(res3, JSON.parse(res3), 3)
    10. $.get("/ajax4", (res4) => {
    11. console.log(res4, JSON.parse(res4), 4)
    12. })
    13. })
    14. })
    15. })
    16. }
    17. script>

    (二)promise

    promise语法:

     (1) promise:

    • Promise是一个 构造函数,  用于创建Promise对象

    • Promise对象:可以理解为一个处理异步操作的容器

     (2) promise对象的三个状态.:

    • pending(进行中)  
    • fulfilled (已成功) 
    • rejected(已失败) 
    • 只有异步操作的结果可以决定当前是哪一种状态  任何其他操作都无法改变这个状态

      (3) promise对象的状态改变:

    • 从pending变为fulfilled  此时应该执行 resolve() 
    • 从pending变为rejected  此时应该执行 reject()
    • 一旦状态改变,就不会再变,任何时候都可以得到这个结果
    • resolve()  和 reject() 只能执行一个

    注:promise本质不是控制 异步代码的执行顺序,而是控制异步代码结果处理的顺序

      (4) 使用:

       1.实例化Promise对象 : 将异步操作放入Promise中 

    • resolve:异步操作 成功状态
    • reject : 异步操作 失败状态

        2.调用then() 方法: 处理异步操作结果

    • promise对象.then((data)=>{ 处理成功数据 },(err)=>{ 处理失败信息 })

      promise静态方法:(常见于笔试题中)

    • Promise.resolve():将现有对象转为 Promise 对象
    1. var p1=Promise.resolve(200)//传入的数据 封装成产生正确数据的Promise对象
    2. console.log(p1) //200
    3. p1.then((data)=>console.log(data))
    4. //等同于
    5. var p1=new Promise((resolve,reject)=>{
    6. resolve(200)
    7. })
    8. p1.then((data)=>console.log(data))
    •  Promise.reject():返回一个新的 Promise 实例  该实例的状态为rejected
    1. var p3=Promise.reject(200) //传入的数据 封装成产生错误数据的Promise对象
    2. console.log(p3) //200
    3. p3.catch(e=>console.log(e)) //200
    •  Promise.all():用于将多个 Promise 实例,包装成一个新的 Promise 实例
    1. var p1=new Promise((n1,n2)=>{
    2. $.get("/ajax1",(data)=>{
    3. n1(data)
    4. })
    5. })
    6. var p2=new Promise((n1,n2)=>{
    7. $.get("/ajax2",(data)=>{
    8. n1(data)
    9. })
    10. })
    11. var p3=new Promise((n1,n2)=>{
    12. $.get("/ajax3",(data)=>{
    13. n1(data)
    14. })
    15. })
    16. var p=Promise.all([p1,p2,p3])
    17. p.then((arr)=>{
    18. conosle.log(arr)
    19. })
    20. /*只有当三个promise对象的状态都为fulfilled,p的状态才会变为fulfilled
    21. 此时p1,p2,p3的返回值组成一个数组,传递给p的回调函数
    22. */
    23. /*只要有一个promise对象被rejected,p的状态就会变成rejected
    24. 此时第一个被rejected的实例的返回值会传递给p的回调函数
    25. */

    (三)Promise解决回调地狱问题 

    原理 :

          在then方法中返回一个promise对象

    • 链式嵌套,需在上一个promise对象的then方法中返回下一个promise对象进而实现连调

     示例:

       解决上述异步回调地狱(回调函数层次嵌套)的问题

    1. function myaxios(url) {
    2. return new Promise((resolve, reject) => {
    3. //封装ajax
    4. try {
    5. //try里的代码3种情况: 语法错误|语法正确但产生错误的业务数据|正确的业务数据
    6. let xhr = new XMLHttpRequest() || ActiveXObject("xxx")
    7. xhr.open("GET", url, true)
    8. xhr.send()
    9. xhr.onreadystatechange = function () {
    10. if (xhr.readyState == 4) {
    11. console.log(123)
    12. if (xhr.status == 200) {
    13. resolve(xhr.responseText)
    14. } else if (xhr.status == 404) {
    15. reject(xhr.responseText)
    16. } else {
    17. reject("net err")
    18. }
    19. }
    20. }
    21. } catch (e) {
    22. reject(xhr.responseText)
    23. }
    24. })
    25. }
    26. var p1 = myaxios('/ajax')
    27. p1.then((data1) => {
    28. console.log(data1)
    29. return myaxios('/ajax1')
    30. })
    31. .then((data2) => {
    32. console.log(data2)
    33. return myaxios('/ajax2')
    34. })
    35. .then((data3) => {
    36. console.log(data3)
    37. return myaxios('/ajax3')
    38. })
    39. .then((data4) => {
    40. console.log(data4)
    41. })
    42. .catch((e) => {
    43. console.log(e)
    44. })

    四、axios网络请求工具

    • 底层是用promise封装ajax封装出来的axios工具 实际是js文件库

       1.引入:同jquery

       2.对以上代码进行优化

    1. var p1=axios('/ajax')
    2. p1.then((data1)=>{
    3. console.log(data1.data)
    4. return axios('/ajax1')
    5. })
    6. .then((data2)=>{
    7. console.log(data2.data)
    8. return axios('/ajax2')
    9. })
    10. .then((data3)=>{
    11. console.log(data3.data)
    12. return axios('/ajax3')
    13. })
    14. .then((data4)=>{
    15. console.log(data4.data)
    16. })
    17. .catch((e)=>{
    18. console.log(e)
    19. })

    五、fetch

    • 是浏览器自带的api 是原生js 不必引入第三方框架 直接使用(前端)
    • 用于发起获取资源的请求
    • 它返回一个 promise,这个 promise 会在请求响应后被 resolve,并传回 Response 对象
    • 采用promise方式但不是promise
    • 底层网络请求不同于ajax和jsonp
    • 虽然功能很好 但不适用于业务

       示例:

    1. // 直接请求ajax1
    2. var res=fetch("/ajax1")
    3. //res是一个promise对象 这个对象内部有后端传过来的二进制包
    4. res.then((data)=>{
    5. return data.json() //调用函数解二进制包
    6. })
    7. .then((result)=>{
    8. console.log(result)
    9. })

    六、fetch ajax和axios 的区别

    写得很详细的一个博主的文章:
    原文链接:https://blog.csdn.net/qq_43539854/article/details/125053587

    七、async 高级函数

    • async函数是ES7中引入的更为高级的异步处理机制, 相当于promise语法的 “高级写法”
    • async和await异步函数 : 这两个关键字只能用于函数,一定要放在async修饰的函数里面
    • async关键字: 修饰函数  表示这个函数内部有异步操作
    • await关键字: 等待异步执行完毕
    • 代码按顺序执行 可维护性好

    async语法

    (1)函数前面使用async修饰

    (2)函数内部:promise操作使用await修饰  await代替then方法取数据

    • await 后面是promise对象, 左侧的返回值就是这个promise对象的then方法中的结果
    • await 只能取出正确的数据
    • await 必须要写在async修饰的函数中,不能单独使用,否则程序会报错
    • await 是遍历器的语法糖

      示例:

      终极高内聚低耦合

    1. let data1=await new Promise((n1,n2)=>{n1(2000)})
    2. console.log(data1) //打印2000
    3. let data2=await axios('/ajax2')
    4. console.log(data2)
    5. let data3=await axios('/ajax3')
    6. console.log(data3)
    7. let data4=await axios('/ajax4')
    8. console.log(data4)
  • 相关阅读:
    自动驾驶感知算法实战2——车载相机及图像处理
    一文介绍使用 JIT 认证后实时同步用户更加优雅
    【英雄哥六月集训】第 24天: 线段树
    DDD项目落地之充血模型实践
    循环结构——求素数个数和平均值
    WPF界面设计
    在Kubernetes上安装和配置Istio:逐步指南,展示如何在Kubernetes集群中安装和配置Istio服务网格
    肖sir__面试就业课___数据库
    Axure8连接不上SVN怎么解决?
    C++容器string的运用和注意
  • 原文地址:https://blog.csdn.net/qq_56668869/article/details/126129117