Ajax 请求是前端使用频率最高的功能之一,虽然现在有各种各样的工具库能够实现快速简洁的调用 Ajax 接口,但是在一些特定项目中,我们可能就是需要使用原生 Ajax 来发送请求。
今天我们就来尝试着使用 Promise 封装一下原生 Ajax,改善其回调冗长的问题。
封装
封装的主要思路就是:
- 如果成功响应,则通过调用 resolve 结束 promise
- 如果响应失败,则通过调用 reject 结束 promise
js
function myAjax(url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState == 4) {
if (this.status == 200) {
// 成功的回调
resolve(this.responseText)
} else {
// 失败的回调
reject(new Error());
}
}
}
xhr.open('get', url)
xhr.send();
})
}
这里要注意一个问题,如果返回的结果中,又有 ajax 请求需要发送,可一定记得使用链式调用,不要在then中直接发起下一次请求,否则,又是地狱见了:
js
// ==== Promise 误区====
myAjax('./d1.json').then(data=>{
console.log(data);
myAjax('./d2.json').then(data=>{
console.log(data)
// ......回调地狱......
})
})
链式的意思就是在上一次 then 中,返回下一次调用的 Promise 对象,我们的代码,就不会进地狱了;
js
myAjax('./d1.json')
.then(data=>{
console.log(data);
return myAjax('./d2.json')
})
.then(data=>{
console.log(data)
return myAjax('./d3.json')
})
.then(data=>{
console.log(data);
})
.catch(err=>{
console.log(err);
})
优化
Promise 的最大问题是代码冗余,原来的任务被 Promise 包装了一下,不管什么操作,一眼看去都是一堆 then,原来的语义变得很不清楚。
我们可以继续使用Async/Await
优化 Ajax 调用的过程。
将整个调用 Ajax 的流程封装成一个 async 函数,在其内部通过 await 控制 ajax 的执行顺序:
js
async function callAjax(){
var a = await myAjax('./d1.json')
console.log(a);
var b = await myAjax('./d2.json');
console.log(b)
var c = await myAjax('./d3.json');
console.log(c)
}
callAjax();
注意:await 关键词 只能在 async 函数内部使用
总结
本文使用了 Promise+Async/await优化了原生 Ajax 连续调用流程不优雅的问题。