axios
Axios 是一个基于 promise 的 HTTP 库,可以用在浏览器和 node.js 中。
优势
- 支持浏览器端
ajax请求 - 支持从
node.js发出http请求 - 支持
Promise Api - 支持拦截请求和响应
- 转换请求和响应数据
- 取消请求
- 自动转换JSON数据
- 客户端支持防范XSRF
支持 Promise Api
axios 使用Promise封装XMLhttpRequest,readyState 改变时会触发 onreadystatechange 事件根据系统或用户配置的状态校验函数 validateStatus 判断执行 resolve 或 reject.
因此在使用axios时可以通过 .then获取正确结果,通过catch处理异常
//核心代码-支持 Promise Api
module.exports = function xhrAdapter(config) {
return new Promise(function dispatchXhrRequest(resolve, reject) {
var request = new XMLHttpRequest();
request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
// Listen for ready state
request.onreadystatechange = function handleLoad() {
settle(resolve, reject, response);
// Clean up request
request = null;
};
request.send(requestData);
});
};
module.exports = function settle(resolve, reject, response) {
var validateStatus = response.config.validateStatus;
if (!response.status || !validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
reject(createError());
}
};
function validateStatus(status) {
return status >= 200 && status < 300;
}
拦截请求和响应
- 可以先拦截请求或响应,然后再由then或处理catch
// Add a request interceptor
axios.interceptors.request.use(function (config) {
return config;
}, function (error) {
return Promise.reject(error);
});
// Add a response interceptor
axios.interceptors.response.use(function (response) {
return response;
}, function (error) {
return Promise.reject(error);
});
在 axios 对象上有一个 interceptors 对象属性,该属性又有 request 和 response 2 个属性,它们都有一个 use 方法,use 方法支持 2 个参数,第一个参数类似 Promise 的 resolve 函数,第二个参数类似 Promise 的 reject 函数。我们可以在 resolve 函数和 reject 函数中执行同步代码或者是异步代码逻辑。
-
工作流程
-
实现逻辑
step1. 定义全局 `this.handlers` 数组,将每个使用`use`方法声明的 2个函数对象插入数组中
step2. 在执行 request请求的时候 将 `interceptors.request` 依次插入执行队列之前 `interceptors.response` 依次插入执行队列之后
step3. 执行队列插入完成之后 通过 while (chain.length) {promise = promise.then(chain.shift(), chain.shift())} 依次执行
- 核心代码
// 插入use声明函数代码
InterceptorManager.prototype.use = function use(fulfilled, rejected) {
this.handlers.push({
fulfilled: fulfilled,
rejected: rejected
});
return this.handlers.length - 1;
};
// 执行请求/响应拦截代码
Axios.prototype.request = function request(config) {
// Hook up interceptors middleware
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
}
取消请求
- 可以使用
CancelToken取消请求。
The axios cancel token API is based on the withdrawn cancelable promises proposal.
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// handle error
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// cancel the request (the message parameter is optional)
source.cancel('Operation canceled by the user.');
因为接口的响应时长是不定的,如果先发出去的请求响应时长比后发出去的请求要久一些,后请求的响应先回来,先请求的响应后回来,就会出现前面请求响应结果覆盖后面请求响应结果的情况,那么就乱了。因此在这个场景下,我们除了做 debounce,还希望后面的请求发出去的时候,如果前面的请求还没有响应,我们可以把前面的请求取消
- 实现逻辑
利用 Promise 实现异步分离,也就是在 `cancelToken` 中保存一个 `pending` 状态的 Promise 对象,然后当我们执行 `cancel` 方法的时候,能够访问到这个 Promise 对象,把它从 `pending` 状态变成 `resolved` 状态,这样我们就可以在 then 函数中去实现取消请求的逻辑,类似如下的代码:
- 核心代码
if (config.cancelToken) {
// Handle cancellation
config.cancelToken.promise.then(function onCanceled(cancel) {
if (!request) {
return;
}
request.abort();
reject(cancel);
// Clean up request
request = null;
});
}
持续更新ing