axios源码阅读

为了方便使用,axios对象既能作对象使用,又能作函数使用.node

axios.post('/user', {
    firstName: 'Fred',
    lastName: 'Flintstone'
  })
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  });
  
axios({
  method: 'post',
  url: '/user/12345',
  data: {
    firstName: 'Fred',
    lastName: 'Flintstone'
  }
});

这一点axios是如何作到的,能够看到instance实际上是一个绑定this的函数,调用axios就是调用context.requestios

function createInstance(){
    // 能当作函数使用的秘密
    var instance = bind(Axios.prototype.request, context);
    // 能当作对象使用的秘密
    utils.extend(instance, Axios.prototype, context);
    // 要拿到构造函数继承的属性
    utils.extend(instance, context);
    return instance
}

var axios = createInstance(defaults);

接下来咱们看一下request方法,全部http请求的发送都会调用Axios.prototype.request,这个函数能够认为是整个axios的骨架,很是重要。axios

Axios.prototype.request = function request(config) {
    // 每一个请求都会从新合成一个config,因此经过操做config对象,你能够标识请求,作某些操做,事实上每一个axios的拦截器都能拿到config对象
    config = utils.merge(defaults, this.defaults, { method: 'get' }, config);
    
    // 挂载拦截器的主要逻辑
    var chain = [dispatchRequest, undefined];
    var promise = Promise.resolve(config);
    
  this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    chain.unshift(interceptor.fulfilled, interceptor.rejected);
  });

  this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    chain.push(interceptor.fulfilled, interceptor.rejected);
  });

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

  return promise;
}

从拦截器中的主要逻辑,咱们能够获得如下几点:promise

  • 发送请求的整个执行顺序是,requestInterceptors ——》dispatchRequest ——》responseInterceptors
  • 拦截器最初接收的对象是config,axios使用中也规定,请求的拦截器必需要返回config,这也是每一个请求拦截器的函数参数是config的缘由
  • 拦截器的执行顺序与interceptors.request.use(function () {/*...*/})执行的顺序有关,即先use的请求拦截器会先执行。
  • 若是拦截器中的函数时async函数,会阻塞整个拦截器链的执行,而transformData不会,因此若是须要对请求的数据作异步处理的话,要在拦截器中完成。

看一下,不一样的http method是怎么复用request方法的缓存

utils.forEach(['delete', 'get', 'head', 'options'], function forEachMethodNoData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url
    }));
  };
});

utils.forEach(['post', 'put', 'patch'], function forEachMethodWithData(method) {
  /*eslint func-names:0*/
  Axios.prototype[method] = function(url, data, config) {
    return this.request(utils.merge(config || {}, {
      method: method,
      url: url,
      data: data
    }));
  };
});

接下来咱们看dispatchRequest的核心逻辑:异步

// 处理config...

var adapter = config.adapter || defaults.adapter;

return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);

// Transform response data
response.data = transformData(
  response.data,
  response.headers,
  config.transformResponse
);

return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
  throwIfCancellationRequested(config);

  // Transform response data
  if (reason && reason.response) {
    reason.response.data = transformData(
      reason.response.data,
      reason.response.headers,
      config.transformResponse
    );
  }
}

return Promise.reject(reason);
});

能够看到dispatchRequest的核心逻辑大概有三步async

  • 处理config
  • 使用adapter发送请求,axios默认内置两个adapter,一个是负责在brower发送请求的,一个是负责在node端发送请求,能够在根文件的defaults下看到
  • 构造响应数据

因此经过dispatchRequest方法的阅读,咱们能够获得如下启示:函数

  • adapter是能够替换的,因此若是你以为你的xhr或http的逻辑更适合业务的须要,彻底能够替换掉,你也彻底能够开发出第三种adapter以处理特定状况,好比开发一个处理缓存的adapter,事实上我如今的项目就是这样作的。
  • 响应的拦截器接收到的是response对象

至此,咱们已经把axios的核心逻辑阅读完毕,从中咱们也能够看到axios的易用性和可拓展性很是强。post

尤为是可拓展性,发送请求到接收响应的过程当中的全部部分几乎都是可拓展的,尤为是config,adapter,interceptor留下了不少想象的空间。this

相关文章
相关标签/搜索