手写axios

//拦截器 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状态 } exactor(cancel) } throwIfRequested() { if(this.reason) { throw this.reason } } source(){ let cancel; //等于上面的cancel,一个函数 const token=new CancelToken(function exactor(c){ cancel=c; }); return { token, cancel } } }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=>{ const {url='',method='get',data=https://www.it610.com/article/{}}=config; //发送请求 const xhr=new XMLHttpRequest(); xhr.open(method,url,true); xhr.onreadystatechange=()=>{ if (xhr.status >= 200 && xhr.status <= 300 && xhr.readyState === 4) { resolve(xhr.responseText) } else { reject('失败了') } }; if(config.cancelToken){ //promise为resolve状态时,取消请求 config.cancelToken.promise.then(function onCancel(reason){//onCancel就是上面的resolvePromise 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{//3个参数(url,data,config),put,post有data return this.request({ method:met, url:arguments[0], data:arguments[1]||{}, ...arguments[2]||{} }) } } }); //继承类的方法及属性 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; }; //引用 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){ //发送之前做什么 return config; },function(err){ //请求出错 return Promise.reject(error) }); axios.interceptors.response.use(function(response){ //响应数据做什么 return response; },function(err){ return Promise.reject(err) })//取消请求 // const {token,cancel}=cancelToken.source(); // config.cancelToken=token; // setTimeout(()=>cancel,500)

    推荐阅读