背景
接口的异步请求方式经历了一系列的变化,由最古老的方式(自己封装 XMLHttpRequest / ActiveXObject);到 jQuery 一招先的年代 ajax 大行其道;再到后面 Promise 的出现后,所有的请求的方式都改成了使用 window.fetch / 类 fetch 的请求方式直接返回一个 Promise 作为请求结果返回,解决了前两方式最容易出现的回调地狱的问题。但使用 Promise.then 的方式还是有一定的局限性,虽然可以使用 Promise.all 来支持迸发请求,但使用起来还不是很爽。直到 ES 7 的 async / await 的出现,
让你完全告别回调地狱的烦恼,写异步像写同步一样爽。
使用 async / await 的异步调用的写法
这里以 Vue 中使用 axios 请求为例
// 前置:axios 接口请求时已做好拦截处理,直接调用 axios 请求时,要么直接返回 data 封装后的正确结果,要么直接抛出异常
getUserName () { // 获得用户名接口
return axios({
method: 'post',
url: '/api/getUserName',
data: {
xxx,
yyy
}
})
}
getMobile () { // 获得到手机号接口
return axios({
method: 'post',
url: '/api/getMobile',
data: {
xxx,
yyy
}
})
}
getDetail (userName, mobile) { // 获得 detail 信息的接口依赖于前面 getUserName 的接口及 getMobile 接口。
return axios({
method: 'post',
url: '/api/getDetail',
data: {
userName,
mobile
}
})
}
async getDetailByUserNameNMobile () { // 结果拼接,【注意:async 里面的所有异步或者同步代码都变成同步一行行执行】
try {
const userName = await this.getUserName()
const getMobile = await this.getMobile()
const result = await this.getDetail(userName, getMobile)
console.log('结果是:', result)
} catch (e) { // 异常处理
console.log(e)
}
}
使用 async / await polyfill 新版的 es 6 异步请求方式 window.fetch
// 参考 https://github.com/bailicangdu/vue2-elm/blob/master/src/config/fetch.js
const baseUrl = 'http://localhost:3000'; // 可换成自己的
export default async (url = '', data = {}, type = 'GET', method = 'fetch') => {
type = type.toUpperCase();
url = baseUrl + url;
if (type == 'GET') {
let dataStr = ''; // 数据拼接字符串
Object.keys(data).forEach(key => {
dataStr += key + '=' + data[key] + '&';
})
if (dataStr !== '') {
dataStr = dataStr.substr(0, dataStr.lastIndexOf('&'));
url = url + '?' + dataStr;
}
}
if (window.fetch && method == 'fetch') {
let requestConfig = {
credentials: 'include',
method: type,
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
mode: "cors",
cache: "force-cache"
}
if (type == 'POST' || type == 'PUT' || type == 'PATCH' || type == 'DELETE') {
requestConfig = {
...requestConfig,
body: JSON.stringify(data)
}
}
try {
const response = type == 'GET' ? await fetch(url) : await fetch(url, requestConfig);
const responseJson = await response.json();
return responseJson;
} catch (error) {
throw new Error(error);
}
} else {
return new Promise((resolve, reject) => {
let requestObj;
if (window.XMLHttpRequest) {
requestObj = new XMLHttpRequest();
} else {
requestObj = new ActiveXObject;
}
let sendData = '';
if (type == 'POST' || type == 'PUT' || type == 'PATCH' || type == 'DELETE') {
sendData = JSON.stringify(data);
}
requestObj.open(type, url, true);
requestObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
requestObj.send(sendData);
requestObj.onreadystatechange = () => {
if (requestObj.readyState == 4) {
if (requestObj.status == 200) {
let obj = requestObj.response
if (typeof obj !== 'object') {
obj = JSON.parse(obj);
}
resolve(obj)
} else {
reject(requestObj)
}
}
}
})
}
}