axios (五)--- Axios 如何支持不同的使用方式?

Axios 中的公共方法 utils

1、关键

axios有几种调用方式,
一种是 axios({}),以函数的方式,传入config就好;
一种是axios.get(), 不只是get,还有axios.request(), axios.post()等
即又有对象属性,又可以用函数方式调用,而 Axios是一个大类,所以可以用bind。
Axios new出来的实例是一个对象,
用bind去生成一个函数,并把Axios上的方法与属性拷贝到实例instance上,就可以用axios()或者
axios.get()去调用

2、使用:

// 方式 1  axios(config)
axios({
    method: 'post',
    url: '/user/123',
    data: {
        firstName: 'Fred',
        lastName: 'feld'
    }
})

// 方式 2  axios(url[, config]),默认 get 请求
axios('http://xxx');

// 方式 3 使用别名进行请求
axios.request(config)
// axios.get(url[, config])
// axios.post(url[, data[, config]])
// axios.put(url[, data[, config]])
// ...

// 方式 4 创建 axios 实例,自定义配置
const instance = axios.create({
  baseURL: 'https://some-domain.com/api/',
  timeout: 1000,
  headers: {'X-Custom-Header': 'foobar'}
});

// axios#request(config)
// axios#get(url[, config])
// axios#post(url[, data[, config]])
// axios#put(url[, data[, config]])
// ...

可见,当我们调用axios()时,实际上是执行了createInstance返回的一个指向Axios.prototype.request的函数;通过添加create方法支持用户自定义配置创建,并且最终也是执行了Axios.prototype.request方法。

3、源码实现

lib/axios.js
let defaults = require('./defaults')
let utils = require('./utils')		// 上一篇有公共方法

function createInstance(defaultConfig) {
    // 创建 axios 实例
    var context = new Axios(defaultConfig);
  
    // 把 instance 指向 Axios.prototype.request 方法
    // bind返回一个新的函数,内部去执行request
    var instance = bind(Axios.prototype.request, context);
  
    // extend 将第二个参数对象的方法拷贝到第一个对象上去
    // 把 Axios.prototype(原型对象) 上的方法扩展到 instance 上,指定上下文是 context 
    // 方法有:request()/get()/post()/put()/delete() 
    utils.extend(instance, Axios.prototype, context);
  
    // 把 context 上的方法扩展到 instance 上
    // 把 Axios实例对象 上的方法扩展到 instance 上,有defaults 和 interceptors属性
    utils.extend(instance, context);
    // 导出 instance 对象
    return instance;
  }

实例一个 axios,并添加create方法
  var axios = createInstance(defaults);
  
  // 添加 create 方法,返回 createInstance 函数,参数为自定义配置 + 默认配置
  axios.create = function create(instanceConfig) {
    return createInstance(mergeConfig(axios.defaults, instanceConfig));
  };
 
    //   ...此处有关拦截的
	// 导出实例 axios
  module.exports = axios;
  
  // Allow use of default import syntax in TypeScript
  module.exports.default = axios;

可见,当我们调用axios()时,实际上是执行了createInstance返回的一个指向Axios.prototype.request的函数;通过添加create方法支持用户自定义配置创建,并且最终也是执行了Axios.prototype.request方法。

也就是说 axios.js 中导出的 axios 对象并不是 new Axios() 方法返回的对象 context,
而是 Axios.prototype.request.bind(context) 执行返回的 instance,
通过遍历 Axios.prototype 并改变其 this 指向到 context;
遍历 context 对象让 instance 对象具有 context 的所有属性。这样 instance 对象就无敌了,😎 既拥有了 Axios.prototype 上的所有方法,又具有了 context 的所有属性。

为什么不能直接用实例对象给我们调用呢?

👆上面就讲到啦,axios有几种调用方式

Axios.js
// 1、配置:外部传入,可覆盖内部默认配置
function Axios(instanceConfig) {
  // 配置
  this.defaults = instanceConfig;
  // ...拦截器实例
}

在看看原型方法 request 做了什么
1、支持多类型传参
2、配置优先级定义
3、通过 promise 链式调用,依次顺序执行

Axios.prototype.request = function request(config) {
    // 为了支持 request(url, {...}), request({url, ...})

    // 方式二:axios('https://xxxx') ,判断参数字符串,则赋值给 config.url
    if (typeof config === 'string') {
      config = arguments[1] || {};
      config.url = arguments[0];
    } else {
      // 方式一:axios({}) ,参数为对象,则直接赋值给 config
      config = config || {};
    }

    // 配置优先级: 调用方法的配置 > 实例化axios的配置 > 默认配置
    // 举个例子,类似:axios.get(url, {}) > axios.create(url, {}) > 内部默认设置
    config = mergeConfig(this.defaults, config);

 	// ...此处关于拦截器链的,具体看下篇
    var promise;
    // 传入配置
    promise = Promise.resolve(config);
    return promise;
  };

对于delete’, ‘get’, ‘head’, 'options,不需要一个个Axios.prototype.delete…去定义,他们的不同除了方法,还有传参,所以只需分成两类,以 Axios.prototype[method] 方式去定义

// Provide aliases for supported request methods   utils.forEach(数组, 函数)-> 循环数组并执行函数
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
    }));
  };
});
// 与平时用的forEach的区别:对象也可以传,并遍历出对象的键值
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
    }));
  };
});

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值