定義Axios類
class Axios{
constructor(){
this.interceptors={
request:new InterceptorsManage,
response:new InterceptorsManage
}
}
request(config){
//攔截器和請求組裝佇列
//成對出現,一個成功一個失敗,失敗回撥暫不處理
let chain=[this.sendAjax.bind(this),undefined];
//請求攔截,呼叫request請求時,請求攔截在前,響應攔截在後
this.interceptors.request.handlers.forEach(inter=>{
chain.unshift(inter.resolve,inter.reject)
})
this.interceptors.response.handlers.forEach(inter=>{
chain.push(inter.resolve,inter.reject)
})
//執行佇列,每次執行一對,並給promise最新的值
let promise=Promise.resolve(config);
while(chain.length>0){
//promise狀態是resolved會執行then中第一個回撥
//1.request.use(成功,失敗),
//2.成功把resolve(config)成功結果給到sendAjax引數執行,
//3.sendAjax執行成功,把結果response給response.use(成功)引數執行
promise=promise.then(chain.shift(),chain.shift())
}
return promise;
}
sendAjax(config){
return new Promise((resolve,reject)=>{
const {url='',method='get',data={}}=config;
//傳送請求
let xhr=new XMLHttpRequest();
xhr.open(method,url,true);
xhr.onreadystatechange=()=>{
if (xhr.status >= 200 && xhr.status <= 300 && xhr.readyState === 4) {
resolve(xhr.responseText)
}
};
if(config.cancelToken){
console.log(111)
//promise為resolve狀態時,取消請求
//onCancel就是上面的resolvePromise也就是promise.resolve()
config.cancelToken.promise.then(function onCancel(reason){
if(!xhr){return}
xhr.abort();//取消請求
reject(reason)
xhr=null;
})
}
xhr.send(data)
})
}
};
定義請求方法
//定義get,post等方法,掛到Axios上
const methodsArr=['get','delete','head','options','put','patch','post'];
methodsArr.forEach(met=>{
Axios.prototype[met]=function(){
console.log('執行'+met+'方法');
//處理單個方法,帶2個引數(url,config)
if(['get','delete','head','options'].includes(met)){
return this.request({
method:met,
url:arguments[0],
...arguments[1]||{}
})
}else{//put,post有data,3個引數(url,data,config)
return this.request({
method:met,
url:arguments[0],
data:arguments[1]||{},
...arguments[2]||{}
})
}
}
});
定義攔截器類
//攔截器
class InterceptorsManage{
constructor(){
this.handlers=[];
}
use(resolve,reject){
this.handlers.push({
resolve,
reject
})
}
}
定義取消請求類
//取消請求
class CancelToken{
constructor(exactor){
//將promise給cancel。防止多次重複cancel
let resolvePromise;//promise例項的resolve方法
this.promise=new Promise(resolve=>{
resolvePromise=resolve;
})
this.reason=undefined;
const cancel=message=>{
if(this.reason){return}
this.reason='cancel'+message;
resolvePromise(this.reason);//改變this.promise為resolve狀態,=resolve('message')
}
exactor(cancel)
}
throwIfRequested() {
if (this.reason) {
throw this.reason
}
}
static source(){
let cancel;//等於上面的cancel,是一個函式
const token=new CancelToken(function exactor(c){
cancel=c;
});
return {
token,
cancel
}
}
}
把定義的方法綁到Axios類上
//繼承類的方法及屬性
function extend(to,from,ctx){
for(let key in from){
//繼承自身屬性,不繼承原型鏈,用hasOwnProperty判斷
if(from.hasOwnProperty(key)){
if(typeof from[key]==='function'){
to[key]=from[key].bind(ctx)
}else{
to[key]=from[key]
}
}
}
return to;
};
匯出axios
//引用
function createInstance(){
let context=new Axios();
//用例項化的context物件去接替Axios類的的request方法,支援axios({...})方法
let instance=Axios.prototype.request.bind(context);
//繼承get,post,put等方法
extend(instance,Axios.prototype,context);
extend(instance,context)
return instance;
}
let axios=createInstance();
//加攔截器
匯出
//引用
function createInstance(){
let context=new Axios();
//用例項化的context物件去接替Axios類的的request方法,支援axios({...})方法
let instance=Axios.prototype.request.bind(context);
//繼承get,post,put等方法
extend(instance,Axios.prototype,context);
extend(instance,context)
return instance;
}
let axios=createInstance();
//加攔截器
axios.interceptors.request.use(function(config){
console.log(config,'config')
//傳送之前做什麼
return config;
},function(err){
//請求出錯
return Promise.reject(error)
});
axios.interceptors.response.use(function(response){
//響應資料做什麼
return response;
},function(err){
return Promise.reject(err)
})
//取消請求
axios.CancelToken=CancelToken;
node程式碼
var express = require('express');
var app = express();
//允許跨域訪問
app.all('*',function(req,res,next){
res.header('Access-Control-Allow-Origin','*');
res.header('Access-Control-Allow-Headers','Content-Type');
res.header('Access-Control-Allow-Methods','*');
res.header('Content-Type','application/json;charset=utf-8');
next();
})
app.get('/index',function(req,res){
data={
'frontEnd':'前端',
'sunny':'陽光'
}
setTimeout(()=>res.json(data),5000)
});
var server = app.listen(3000, function(){
console.log("伺服器啟動");
});
html頁面
<html>
<script type="text/javascript" src="./index.js"></script>
<body>
<button id="btn">傳送</button>
<script>
document.getElementById('btn').onclick= function(){
const cancelToken=axios.CancelToken;
const {token,cancel}=cancelToken.source();
axios.get('http://localhost:3000/index',{cancelToken:token})
.then(res=>console.log(res,'rrr'))
.catch(e=>console.log(e,'eee'))
setTimeout(()=>cancel('取消了~'))
}
</script>
</body>
</html>