2020-11-11
原生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