关于javascript:axios源码学习关键知识点之拦截器

30次阅读

共计 3536 个字符,预计需要花费 9 分钟才能阅读完成。

1. 拦截器应用办法

// 申请拦截器 1
 axios.interceptors.request.use(options => {console.log('1')
    return options
 })
 // 申请拦截器 2
 axios.interceptors.request.use(options => {console.log('2')
    return options
 })

相应拦截器

// 相应拦截器 1
axios.interceptors.response.use(options => {console.log('2')
   return options
})
// 响应拦截器 2
axios.interceptors.response.use(options => {console.log('1')
   return options
})

发送申请

axios(options).then(function (res) {}).catch(function (res) {});

执行成果

留神点:申请拦截器先退出的后执行,响应拦截器先退出的先执行

2. 拦截器对应源码实现

axios.interceptors.response.use 调用的对应函数 \lib\core\InterceptorManager.js

InterceptorManager.prototype.use = function use(fulfilled, rejected, options) {
  this.handlers.push({
    fulfilled: fulfilled,
    rejected: rejected,
    synchronous: options ? options.synchronous : false,
    runWhen: options ? options.runWhen : null
  });
  return this.handlers.length - 1;
};

接管拦截器执行胜利回调,失败回调和配置参数,上方示例只增加了拦截器执行胜利回调,相当于 rejected 是 undefined, return this.handlers.length – 1 返回以后拦截器的 id,不便后续勾销拦截器

顺便看下拦截器的勾销

InterceptorManager.prototype.eject = function eject(id) {if (this.handlers[id]) {this.handlers[id] = null;
  }
};

将对应 id 的拦截器置为空,想勾销拦截器即可调用 axios.interceptors.request.eject(1),这里勾销了索引为 1,即第二个申请拦截器

拦截器与真正申请的组合调用形式

axios(options).then(function (res) {}).catch(function (res) {}); 发送申请时,执行了 Axios.prototype.request

Axios.prototype.request = function request(config) {
  // filter out skipped interceptors
  var requestInterceptorChain = [];
  var synchronousRequestInterceptors = true;
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    // options ? options.synchronous : false,
    synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
    // 向数组结尾增加(多个参数示意多个元素)// 为什么间接拜访了 interceptor.fulfilled 而不是 interceptor.handlers.fulfilled,
    requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

  var responseInterceptorChain = [];
  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
  });

  var promise;

  if (!synchronousRequestInterceptors) {var chain = [dispatchRequest, undefined];
    // unshift() 办法可向数组的结尾增加一个或更多元素,并返回新的长度。Array.prototype.unshift.apply(chain, requestInterceptorChain);
    chain.concat(responseInterceptorChain);

    /* 将现有对象转为 Promise 对象
    Promise.resolve('foo')
     // 等价于
    new Promise(resolve => resolve('foo')) */
    promise = Promise.resolve(config);
    while (chain.length) {
      // 调用拦截器,申请连
      promise = promise.then(chain.shift(), chain.shift());
    }

    return promise;
  }


  var newConfig = config;
  while (requestInterceptorChain.length) {
    // 删除第一个元素并返回第一个元素
    var onFulfilled = requestInterceptorChain.shift();
    var onRejected = requestInterceptorChain.shift();
    try {newConfig = onFulfilled(newConfig);
    } catch (error) {onRejected(error);
      break;
    }
  }

  try {promise = dispatchRequest(newConfig);
  } catch (error) {return Promise.reject(error);
  }

  while (responseInterceptorChain.length) {promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
  }

  return promise;
};

上方源码只粘贴了次要代码
别离遍历申请拦截器个响应拦截器,像申请拦截器数组后方和响应拦截器前方顺次增加拦截器胜利回调和失败回调,定义一个真正发动申请时执行的函数数组 var chain = [dispatchRequest, undefined]; 别离在后方退出申请拦截器,前方退出返回拦截器,最初 chain 形如

[申请拦截器胜利回调函数,申请拦截器失败回调函数,dispatchRequest,undefined,响应拦截器胜利回调函数,响应拦截器失败回调函数]

遍历 chain 顺次用 promise 链去执行:如:

while (chain.length) {
      // 调用拦截器,申请连
      promise = promise.then(chain.shift(), chain.shift());
    }

测试执行过程

let fun1 = function (e) {console.log('拦截器 1 胜利函数', '上一个函数返回的参数', e)
    return 1
  }
  let fun2 = function (e) {console.log('真正发动申请',  '上一个函数返回的参数', e)
    return 2
  }
  let fun3 = function (e) {console.log('响应拦截器 1 胜利函数', '上一个函数返回的参数', e)
    return 3
  }
  let arr = [fun1, undefined, fun2, undefined, fun3, undefined]
  let promise = Promise.resolve(9);
  while (arr.length) {promise = promise.then(arr.shift(), arr.shift());
  }
   promise.then(res => {console.log('最初拿到的数据', res)
   })

执行后果

更多对于 axios 的具体解析:若川大佬的源码解析系列

正文完
 0