关于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来生产一些列操作。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理