axios三部曲三极简核心造轮子
Posted Tony
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了axios三部曲三极简核心造轮子相关的知识,希望对你有一定的参考价值。
axios执行流程
目录结构
如果要一个极简核心的话,我们只需要 request 请求函数,和一个 XMLHttpRequest 即可,拦截器,适配器 dispatchRquest 都可以不要
Axios构造函数
我们从Axios构造函数开始写
core/Axios.js
import utils from "../utils";
import mergeConfig from "./mergeConfig";
import xhr from "./xhr";
// 核心文件
function Axios(config)
this.defaults = config;
Axios.prototype.request = function (config)
// 处理axios(url[,config])
if (typeof config === "string")
config = arguments[1] || ;
config.url = arguments[0];
else
config = config || ;
// 合并config
config = mergeConfig(this.defaults, config);
console.log(config);
// 设置默认method
if (config.method)
config.method = config.method.toLowerCase();
else if (this.defaults.method)
config.method = this.defaults.method.toLowerCase();
else
config.method = "get";
let promise = Promise.resolve(config);
promise = promise.then(xhr);
return promise;
;
utils.forEach(["delete", "get", "head", "options"], function (method)
Axios.prototype[method] = function (url, config)
return this.request(
utils.merge(config || ,
method: method,
url: url,
)
);
;
);
utils.forEach(["post", "put", "patch"], function (method)
Axios.prototype[method] = function (url, data, config)
return this.request(
utils.merge(config || ,
method: method,
url: url,
data: data,
)
);
;
);
export default Axios;
只有一个最简单request方法
mergeConfig
core/mergeConfig.js
也没有做过多的判断,只是优先把config2的值拷贝到config上,其次再使用config1的值
import utils from "../utils";
// 合并两个配置对象,返回一个新的对象
function mergeConfig(config1, config2)
let config = ;
let axiosKeys = Array.from(
new Set(Object.keys(config1).concat(Object.keys(config2)))
);
// 优先使用config2身上的
utils.forEach(axiosKeys, function (prop)
if (utils.isObject(config2[prop]))
config[prop] = utils.merge(config1[prop], config2[prop]);
else if (typeof config2[prop] !== "undefined")
config[prop] = config2[prop];
else if (utils.isObject(config1[prop]))
config[prop] = utils.merge(config1[prop]);
else if (typeof config1[prop] !== "undefined")
config[prop] = config1[prop];
);
return config;
export default mergeConfig;
xhr
core/xhr.js
一个简单的XMLHttpRequest
// XMLHttpRequest
// 返回一个promise
const xhr = function (config)
return new Promise(function (resolve, reject)
let xhr = new XMLHttpRequest();
xhr.open(config.method, config.url);
xhr.send(config.data);
xhr.onreadystatechange = function ()
if (xhr.readyState === 4)
if (xhr.status >= 200 && xhr.status < 300)
// 返回response数据,自定义格式
resolve(
config: config,
data: JSON.parse(xhr.responseText),
request: xhr,
headers: xhr.getAllResponseHeaders(),
status: xhr.status,
statusText: xhr.statusText,
);
else
reject("数据请求错误:" + xhr.statusText);
;
);
;
export default xhr;
utils
utils.js
一些工具函数
function forEach(obj, fn)
if (obj === null || typeof obj === "undefined")
return;
if (typeof obj !== "object")
obj = [obj];
if (Array.isArray(obj))
for (let i = 0; i < obj.length; i++)
fn.call(null, obj[i], i, obj);
else
for (let key in obj)
if (Object.prototype.hasOwnProperty.call(obj, key))
fn.call(null, obj[key], key, obj);
function bind(fn, thisArg)
// 这里用fn.apply来实现函数this绑定,注意需要返回的也是一个函数,所以这里包一层
return function wrap()
// 把多个参数,转成数组的形式
let args = new Array(arguments.length);
for (let i = 0; i < args.length; i++)
args[i] = arguments[i];
// args是一个数组,apply调用方式
return fn.apply(thisArg, args);
;
// 实现继承,b->a 如果是函数要绑定this指向
function extend(a, b, thisArg)
forEach(b, function (val, key)
if (thisArg && typeof val === "function")
a[key] = bind(val, thisArg);
else
a[key] = val;
);
return a;
// 合并对象,返回一个新的对象
function merge()
let result = ;
function assignValue(val, key)
// result里的是一个对象,并且val也是一个对象,深拷贝
if (typeof result[key] === "object" && typeof val === "object")
result[key] = merge(result[key], val);
else if (typeof result[key] === "object")
result[key] = merge(, val);
else
result[key] = val;
// 有多个参数要合并,依次循环遍历,合并到result
for (let i = 0; i < arguments.length; i++)
forEach(arguments[i], assignValue);
return result;
function isObject(val)
return val !== null && typeof val === "object";
export default
forEach,
bind,
extend,
merge,
isObject,
;
defaults
defaults.js
默认的头配置文件
let defaults =
method: "get",
;
export default defaults;
axios入口文件
// 入口文件
import Axios from "./core/Axios";
import utils from "./utils";
import mergeConfig from "./core/mergeConfig";
import defaults from "./defaults";
function createInstance(defaultConfig)
let context = new Axios(defaultConfig);
let instance = utils.bind(Axios.prototype.request, context);
// extend prototype
utils.extend(instance, Axios.prototype, context);
// extend Axios属性
utils.extend(instance, context);
instance.create = function (newConfig)
return createInstance(mergeConfig(defaultConfig, newConfig));
;
return instance;
let axios = createInstance(defaults);
console.dir(axios);
// console.log(axios);
// axios(
// url: "http://localhost:3000/posts",
// method: "get",
// ).then((response) =>
// console.log(response);
// );
axios
.get("http://localhost:3000/posts",
headers:
common: 111,
,
)
.then((response) =>
console.log(response);
);
总结
- promise的使用
- utils里面的工具函数比较实用,要注意的是forEach,bind,extend,merge这几个函数
- 构造函数 + prototype的方式来组织代码,现在已经有更好的选择 class
- axios库的核心就是axios是一个函数(request),它身上也挂有方法(get,post),我们可以学习这种编程方法
- axios的config参数合并也是重点,有优先级,默认的最低,最后方法传入的最高
源码地址
以上是关于axios三部曲三极简核心造轮子的主要内容,如果未能解决你的问题,请参考以下文章
别再重复造轮子了,推荐使用 Google Guava 开源工具类库,真心强大!