欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

2020-11-11

程序员文章站 2022-06-17 23:46:02
错误封装原生ajax导致无法获取请求结果一. 前奏——了解ajax文档ajax文档地址XMLHttpRequest 的实例对象拥有:两个请求方法:open(method,url,async),send(string);两种响应字段:responseText(字符串形式),responseXML(xml形式)三个属性:onreadystatechange(实例状态改变调用的函数),readyState(实例状态),status(状态)二、错误封装原生ajax......

原生ajax的封装以及结合promise和async/await的使用

一. 前奏——了解ajax文档
ajax文档地址
XMLHttpRequest 的实例对象拥有:

  • 两个请求方法:open(method,url,async),send(string);

  • 两种响应字段:responseText(字符串形式),responseXML(xml形式)

  • 三个属性:onreadystatechange(实例状态改变调用的函数),readyState(实例状态),status(状态)

二、错误封装原生ajax
(第一种错误范例)

import Vue from 'vue'
function xmlhttpFun(type, url, judge, ) {
    var xmlhttp;
    var res;
    if (window.XMLHttpRequest) {
        //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
        xmlhttp = new XMLHttpRequest();
    }
    else {
        console.log('ActiveXObject')
        // IE6, IE5 浏览器执行代码
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function () {
        console.log(xmlhttp.readyState, xmlhttp.status, xmlhttp);

        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {   // 请求成功
            return(JSON.parse(xmlhttp.responseText)) 
        }else{
            return
        }
    }
    xmlhttp.open(type, url, judge);
    xmlhttp.send();
}
Vue.prototype.$xmlhttp = xmlhttpFun
export default xmlhttpFun


------------------------------------------------vue文件中调用该函数
let s =  this.$xmlhttp("get", "/api/customer", true);
console.log('s',s);

封装xmlhttpFun方法,会想如何让外界拿到这个值,然后就在onreadystatechange方法内部return。问题来了,因为onreadystatechange方法在xmlhttpFun方法内部,调用该方法只会得到undefined。
然后就会想能不能把return提到xmlhttpFun方法内部,然后就有了第二种错误范例
(第二种错误范例)

import Vue from 'vue'
function xmlhttpFun(type, url, judge, ) {
    var xmlhttp;
    var res;
    if (window.XMLHttpRequest) {
        //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
        xmlhttp = new XMLHttpRequest();
    }
    else {
        console.log('ActiveXObject')
        // IE6, IE5 浏览器执行代码
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function () {
        console.log(xmlhttp.readyState, xmlhttp.status, xmlhttp);

        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {   // 请求成功
            res = JSON.parse(xmlhttp.responseText)
        }else{
            return
        }
    }
    xmlhttp.open(type, url, judge);
    xmlhttp.send();
    return res;
}
Vue.prototype.$xmlhttp = xmlhttpFun
export default xmlhttpFun
------------------------------------------------vue文件中调用该函数
let s =  this.$xmlhttp("get", "/api/customer", true);
console.log('s',s);
------------------------------------------------log结果
1 0 XMLHttpRequest {onreadystatechange: ƒ, readyState: 1, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
s undefined
2 200 XMLHttpRequest {onreadystatechange: ƒ, readyState: 2, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
3 200 XMLHttpRequest {onreadystatechange: ƒ, readyState: 3, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
4 200 XMLHttpRequest {onreadystatechange: ƒ, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}

该范例添加全局变量res,当拿到数据后再return出去,但是结果还是undefined,为什么呢?
看log结果会发现,诶?我状态还没正确(xmlhttp.readyState == 4 && xmlhttp.status == 200)就已经返回值了。
然后就想到,之前open方法是异步调用的,那我是不是用同步可以解决呢?

------------------------------------------------vue文件中调用该函数
let s =  this.$xmlhttp("get", "/api/customer", false);
console.log('s',s);
------------------------------------------------log结果
1 0 XMLHttpRequest {onreadystatechange: ƒ, readyState: 1, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
4 200 XMLHttpRequest {onreadystatechange: ƒ, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
s {code: 200, msg: "请求成功", data: Array(1)}

看结果是可以用同步解决,但现实问题是不可能让所有请求都同步进行。接下来继续异步研究,那么该用什么方法能拿到异步返回结果呢?
对,回调函数。
看代码:(第三种范例 !!!正确的)

import Vue from 'vue'

function xmlhttpFun(type, url, judge, callbackFun) {
    // AJAX = 异步(Asynchronous   [eɪˈsɪŋkrənəs] ) JavaScript + XML
    var xmlhttp;
    var res;
    if (window.XMLHttpRequest) {
        //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
        xmlhttp = new XMLHttpRequest();
    }
    else {
        console.log('ActiveXObject')
        // IE6, IE5 浏览器执行代码
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function () {
        console.log(xmlhttp.readyState, xmlhttp.status, xmlhttp);

        if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {   // 请求成功
            res = JSON.parse(xmlhttp.responseText)
            callbackFun(res)
        }
    }
    xmlhttp.open(type, url, judge);
    xmlhttp.send();
}

Vue.prototype.$xmlhttp = xmlhttpFun
export default xmlhttpFun
------------------------------------------------vue文件中调用该函数
this.$xmlhttp("get", "/api/customer",true, function(val){
    console.log('回调函数获取异步值:',val);
});
------------------------------------------------log结果
1 0 XMLHttpRequest {onreadystatechange: ƒ, readyState: 1, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
2 200 XMLHttpRequest {onreadystatechange: ƒ, readyState: 2, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
3 200 XMLHttpRequest {onreadystatechange: ƒ, readyState: 3, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
4 200 XMLHttpRequest {onreadystatechange: ƒ, readyState: 4, timeout: 0, withCredentials: false, upload: XMLHttpRequestUpload,}
回调函数获取异步值: {code: 200, msg: "请求成功", data: Array(1)}

如图,回调拿到返回值了!
但是还有问题 (我异步连续调用会出现地狱回调)
如图:

let that = this
  this.$xmlhttp("get", "/api/customer", true, function(val) {
  	console.log("回调函数获取异步值:", val);
  	that.$xmlhttp("get", "/api/customer", true, function(val) {
       console.log("回调函数获取异步值:", val);
       that.$xmlhttp("get", "/api/customer", true, function(val) {
         console.log("回调函数获取异步值:", val);
       });
     });
   });

三、结合promise,解决地狱回调问题
promise文档

promise的三种状态:pending(进行中)、fulfilled(已成功)和rejected(已失败)
promise控制状态的两种方法:resolve rejecte,

import Vue from 'vue'

function xmlhttpFun(type, url, judge) {
    // AJAX = 异步(Asynchronous   [eɪˈsɪŋkrənəs] ) JavaScript + XML
    return new Promise((resolve, reject) => {
        var xmlhttp;
        if (window.XMLHttpRequest) {
            //  IE7+, Firefox, Chrome, Opera, Safari 浏览器执行代码
            xmlhttp = new XMLHttpRequest();
        }
        else {
            console.log('ActiveXObject')
            // IE6, IE5 浏览器执行代码
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        }
        xmlhttp.onreadystatechange = function () {
            // console.log(xmlhttp.readyState, xmlhttp.status, xmlhttp);

            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {   // 请求成功
                resolve(JSON.parse(xmlhttp.responseText))
            }else{
                return
            }
        }
        xmlhttp.open(type, url, judge);
        xmlhttp.send();
    })
}

Vue.prototype.$xmlhttp = xmlhttpFun
export default xmlhttpFun
------------------------------------------------vue文件调用
this.$xmlhttp("get", "/api/customer", true).then(res => {
  console.log("返回第一个函数的promise对象:", res);
  return this.$xmlhttp("get", "/api/customer", true)
})
.then(res=>{
  console.log("返回第二个函数的promise对象:", res);
  return this.$xmlhttp("get", "/api/customer", true)
})
.then(res=>{
  console.log("返回第三个函数的promise对象:", res);
})

对比使用promise前后函数的调用方式,promise就是让调用看起来更加简介明了,一目了然
那配合async await 使用会有什么效果呢?
四、配合async await同步调用

------------------------------------------------vue文件调用
async handleSend() {
      let resFirst = await this.$xmlhttp("get", "/api/customer", true)
      let resSecond = await this.$xmlhttp("get", "/api/customer", true)
      let resThird = await this.$xmlhttp("get", "/api/customer", true)
      console.log('resFirst',resFirst);
      console.log('resSecond',resSecond);
      console.log('resThird',resThird);
  }
 ------------------------------------------------log结果
resFirst {code: 200, msg: "请求成功", data: Array(1)}
resSecond {code: 200, msg: "请求成功", data: Array(1)}
resThird {code: 200, msg: "请求成功", data: Array(1)}

使用之后看起来更加简介明了 ,但是要结合实际情况适用async await。毕竟不可能让请求都去同步执行,效率太低下。
五、结尾
今天研究了 ajax的封装promise解决地狱回调async await同步调用三个点,如果有错还请指出来共同学习~

本文地址:https://blog.csdn.net/qq_19652407/article/details/109627594