乐趣区

关于javascript:axios如何实现interceptors

接口分析

https://github.com/axios/axio…
一般用法

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Any status code that lie within the range of 2xx cause this function to trigger
    // Do something with response data
    return response;
  }, function (error) {
    // Any status codes that falls outside the range of 2xx cause this function to trigger
    // Do something with response error
    return Promise.reject(error);
  });

删除拦截器

const myInterceptor = axios.interceptors.request.use(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);

同步解决

axios.interceptors.request.use(function (config) {
  config.headers.test = 'I am only a header!';
  return config;
}, null, {synchronous: true});

条件执行

function onGetCall(config) {return config.method === 'get';}
axios.interceptors.request.use(function (config) {
  config.headers.test = 'special get headers';
  return config;
}, null, {runWhen: onGetCall});

提出问题:
a. interceptor 是如何实现申请的前置解决和后置解决?
b. 为什么 request interceptor 要思考同步执行?
https://github.com/axios/axio… 里提到,默认 synchronous 为 false,是异步执行的。当 js 主线程梗塞的时候,就会导致提早执行 request interceptor。这里波及到了 event loop 模型的常识,js 引擎会先执行同步代码,执行完了,会去查看工作队列,看看有没有异步工作的后果,有的话推送到执行栈执行。那咱们上面看看它是如何实现同步执行的。

源码剖析

  1. 提取关键字interceptors,定位到Axios.jsInterceptorManager.js
  2. 查看 InterceptorManager.js

    var utils = require("./../utils");
    function InterceptorManager() {this.handlers = [];
    }
    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;
    };
    // 重置 interceptor 为 null,留神不是删除
    InterceptorManager.prototype.eject = function eject(id) {if (this.handlers[id]) {this.handlers[id] = null;
     }
    };
    // 专属的递归器,次要逻辑就是如果不是 null 就执行执行器
    InterceptorManager.prototype.forEach = function forEach(fn) {
     utils.forEach(this.handlers,
     function forEachHandler(h) {if (h !== null) {fn(h);
         }
     });
    };
    module.exports = InterceptorManager;

    顺便贴一下 util.js 的 forEach 办法,实质上就是对 obj 进行 for 循环,对每个元素执行回调

    function forEach(obj, fn) {
     // Don't bother if no value provided
     if (obj === null || typeof obj === 'undefined') {return;}
    
     // Force an array if not already something iterable
     if (typeof obj !== 'object') {
         /*eslint no-param-reassign:0*/
         obj = [obj];
     }
    
     if (isArray(obj)) {
         // Iterate over array values
         for (var i = 0,
         l = obj.length; i < l; i++) {fn.call(null, obj[i], i, obj);
         }
     } else {
         // Iterate over object keys
         for (var key in obj) {if (Object.prototype.hasOwnProperty.call(obj, key)) {fn.call(null, obj[key], key, obj);
             }
         }
     }
    }
    

    小结一下,InterceptorManager 类,设计了收集、移除、递归 interceptor 的性能

  3. 再看 Axios.js
    line18~21:初始化 intercepor

    this.interceptors = {request: new InterceptorManager(),
     response: new InterceptorManager()};

    line60~118: 过滤 interceptors,并合并解决

    var requestInterceptorChain = [];
    var synchronousRequestInterceptors = true;
    // 用 InterceptorManager 的 forEach 办法,曾经过滤为 null 的 interceptor
    this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {return;}
     // 对于同步执行的 request 相干的 interceptor 逻辑,前面咱们再回头来看。这里的逻辑就是要么全副是同步执行,要么全副是异步执行。只有有一个是异步,则全副用异步的办法执行。synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
    
     requestInterceptorChain.unshift(interceptor.fulfilled, interceptor.rejected);
    });
    
    var responseInterceptorChain = [];
    this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {responseInterceptorChain.push(interceptor.fulfilled, interceptor.rejected);
    });
    
    var promise;
    // request 的 interceptor 以异步模式执行
    if (!synchronousRequestInterceptors) {// 这里要结构 [onFullfilled, onRejected] 格局,以便下边应用 promise.then 办法来执行。var chain = [dispatchRequest, undefined];
     // 合并操作:先执行 request 的 interceptor,再发动申请,最初再执行 response 的 interceptor
     Array.prototype.unshift.apply(chain, requestInterceptorChain);
     chain.concat(responseInterceptorChain);
     // 新建 proise,并执行。所以 interceptor 的原理是在发动申请前做一些列操作,而后发动申请,最初执行返回后的操作。很天然会想到 promise 操作
     promise = Promise.resolve(config);
     while (chain.length) {promise = promise.then(chain.shift(), chain.shift());
     }
    
     return promise;
    }
    // request 的 interceptor 以同步模式执行
    var newConfig = config;
    while (requestInterceptorChain.length) {var onFulfilled = requestInterceptorChain.shift();
     var onRejected = requestInterceptorChain.shift();
     try {
         // 同步执行 onFulfilled 办法
         newConfig = onFulfilled(newConfig);
     } catch(error) {
         // 同步执行 onRejected 办法
         onRejected(error);
         break;
     }
    }
    // 异步发动申请
    try {promise = dispatchRequest(newConfig);
    } catch(error) {return Promise.reject(error);
    }
    // 异步执行 response 的 interceptor
    while (responseInterceptorChain.length) {promise = promise.then(responseInterceptorChain.shift(), responseInterceptorChain.shift());
    }
    return promise;
    };

    小结一下,Axios.js 这段操作,次要做了一下这些工作:

    • 过滤 request 的 interceptor:通过 forEach 办法、runWhen 参数
    • 决定 request 的 interceptor 是同步执行还是异步执行:因为批处理,要么都是同步执行,要么都是异步执行
    • 把符合要求 request interceptor 推入 requestInterceptorChain
    • 过滤 response 的 interceptor:通过 forEach 办法
    • 把符合要求 response interceptor 推入 responseInterceptorChain
    • 如果 request 的 interceptor 是异步执行,那么合并操作:request interceptor、发动申请、response interceptor,用 promise.then 操作来生产这些操作
    • 如果 request 的 interceptor 是同步执行,那么同步执行 request 的 interceptor,而后用 promise.then 异步发动申请、异步解决 response interceptor
    • 返回 promise

值得借鉴的中央

  1. InterceptorManager 的实现中,eject 办法,是间接置 null,而不是删除元素。如果须要无效的元素,则再写一个过滤办法来获取。这样的益处的不会扭转前面元素的 index。
  2. 结构 [onFullfilled, onRejected] 数据格式,巧用 promise.then 来生产一系列操作。

总结

  1. interceptor 自身就是一个收集解决的对象
  2. axios 是通过合并前置操作、发动申请、后置操作,而后用 promise.then 来生产一些列操作。
退出移动版