• axios源码学习


    0 axios创建实例

    axios可以通过create方法创建多个实例,创建的实例对象也可以调用create方法再次创建示例,好处在于可以复用公共的示例对象配置

    function createInstance(defaultConfig) {
    	instance.create = function create(instanceConfig) {
    		return 	createInstance(mergeConfig(defaultConfig,instanceConfig))
    	}
    	return instance
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    1 判断一个对象是否普通对象

    • Symbol.toStringTag:可以修改Object.prototype.toString.call返回的后缀,普通对象自带该属性,不需要设置,如果设置说明该对象不是普通对象
    • Symbol.iterator:拥有该属性的对象可以使用for of进行遍历,普通对象没有该属性
    //Object.propotype 指向null 说明它是最后的Object
    //
    const isPlainObject = (val) => {
    	const str = Object.prototype.toString.call(val)
    	const type = str.slice(8,-1).toLowerCase();
    	if (type !== 'object') {
    		return false	
    	}
    	//是object
    	const prototype = Object.getPropertyOf(val);
    	return (prototype === Object.prototype || prototype === null || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in val) && !(Symbol.iterator in val)
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2 遍历对象,使对象每一项执行绑定的函数

    const foreach = (obj, fn) => {
    	if(obj === null || typeof obj === 'undefined') return;
    	let i,l;
    	//如果不是对象,使用数组包裹
    	if (typeof obj !== 'object' ) {
    		obj = [obj]
    	}
    	//遍历数组
    	if (Array.isArray(obj)) {
    		for(i=0, l=obj.length; i<l;i++) {
    			fn.call(null, obj[i], i)
    		}
    	} else {
    		//对象的所有键名
    		const keys = Object.keys(obj)
    		for(let i =0; i<keys.length; i++) {
    			const key = keys[i]
    			fn.call(null, obj[key], key)
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    3 对象继承和改变继承对象的this

    const extend = (a: object, b: object, thisArg: object) => {
    	foreach(b, (val, key) => {
    		// 如果指定了thisArg, 并且键值是一个函数
    		if (thisArg && typeof val === 'function') {
    			a[key] = val.bind(thisArg);
    		} else {
    			a[key] = val;	
    		}
    	})
    	return a;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    4 合并对象属性,相同属性后面的替换前面的

    const merge = () {
    	let result = {};
    	const assignValue = (val, key) => {
    		//如果遍历的值为对象类型,则需要深度遍历
    		if (typeof val === 'object' ) {
    			result[key] = merge(result[key], val)
    		} else {
    			result[key] = val;
    		}
    	};
    	for(let i = 0; i<arguments.length; i++) {
    		foreach(arguments[i], assignValue)
    	}
    	return result
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    5 request函数

    axios的使用如下:
    common表示对于任何类型的请求都要添加该属性,method表示只有该类型的请求方法才会添加对应的属性

    axios.defaults.headers.common['test'] = 123
    axios.defaults.headers.post['Content-Type'] = 'application/x-www/'
    
    • 1
    • 2
    //两种形式
    //axios('/test')
    //axios({pathname: '/test',})
    
    const request = (configOrUrl, config) {
    	//首先判断第一个参数是不是url
    	if (typeof configOrUrl === 'string' ) {
    		config = config || {};	//get请求没有config
    		config.url = configUrl	
    	} else {
    		config = configOrUrl || {}
    	}
    	//兼容以前的版本在新版本中移除、自定义序列化参数、请求头
    	const { transitional, paramsSerializer, headers } = config;
    	
    	if(paramsSerializer !== null) {
    		...	
    	}
    	
    	//设置请求方法
    	config.method = (config.method || 'get').toLowerCase();
    	
    	//需要将headers中共有的属性和私有属性进行合并
    	let contextHeaders = merge(headers.common, headers[config.method])
    	
    	//删除headers中的这些属性
    	foreach(['delete', 'get', 'head', 'post', 'put', 'patch', 'common'], (method) => {
    		delete headers[method];	
    	})
    	
    	//筛选除跳过的拦截, 由于eject会移除拦截器,但是索引会被保留,因此需要forEach跳过值为null的函数
    	const requestInterceptorChain = [];
    	let synchronousRequestInterceptors = true;
    	//传入runWhen方法,如果runWhen返回值为false则忽略这个拦截器
    	this,interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
    		if (typeof interceptor.runWhen === 'function' && interceptor.runWhen(config) === false) {
    			return;	
    		}
    		//是否同步执行
    		synchronousRequestInterceptors = synchronousRequestInterceptors && interceptor.synchronous;
    		//先执行最后的回调,在执行前面的,因此拦截器添加方式后来的放在数组前面
    		requestInterceptorChain.unshift(interceptor.fulfilled,interceptor.rejected)
    	})
    	
    	 const responseInterceptorChain = [];
    	 this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
    	 	responseInterceptorChain.push(interceptor.fulfilled,interceptor.rejected)
    	 })
    	
    	//异步执行请求拦截器
    	let promise;
    	let i=0;
    	let len;
    	if (!synchronousRequestInterceptors) {
    		const chain = [dispatchRequest, undefined];
    		//将请求拦截器放到chain头部
    		Array.prototype.unshift.apply(chain, requestInterceptorChain);
    		chain.push.apply(chain,responseInterceptorChain);
    		len = chain.length;
    		promise - Promise.resolve(config);	
    		//组合形成promise执行链	
    		while (i<len) {
    			promise = promise.then(chain.shift(),chain.shift())	
    		}
    		return promise
    	}
    
    	len = requestInterceptorChain.length;
    	
    	let newConfig = config;
    	i = 0;
    	while (i<len) {
    		const onFulfilled = requestInterceptorChain[i++];
    		const onRejected = requestInterceptorChain[i++];
    		try {
    			//执行请求拦截器的then方法
    			newConfig = onFulfilled(newConfig)
    		} catch (error) {
    			onRejected.call(this, error);
    			break;
    		}
    	}
    	try {
    		promise = dispatchRequest(newConfig);	
    	} catch (error) {
    		return Promise.reject(error);	
    	}
    	//循环执行所有相应拦截器
    	while (responseInterceptorChain.length) {
    		promise = promise.then(responseInterceptorChain[i++], responseInterceptorChain[i++])
    	}
    	return promise
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94

    6 取消请求

    const token = axios.CancelToken
    const source = token,source()
    axios.get('', {
    	cancelToken: source.token,
    })
    
    source.cancel()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    class CancelToken {
    	constructor(executor) {	
    		if (typeof executor !== 'function') {
    			throw new TypeErroe('执行器必须要是一个函数')
    		}
    		//创建一个pending状态的对象, 将resolvePromise变量指向resolve函数
    		let resolvePromise;
    		 this.promise = new Promise(function promiseExecutor(resolve) {
    		 	resolvePromise = resolve	
    		 })
    		 //传入cancel函数,在函数内部调用resolvePromise将Promise对象从pending状态变为resolved状态
    		 executor(message => {
    		 	if (this.reason) return 
    		 	this.reason = message
    		 	resolvePromise(this.reason)	
    		 })
    		
    	}	
    	//不能通过类的实例调用,只能通过类本身调用
    	static source() {
    		let cancel;
    		const token = new CancelToken(function executor(c) {
    			cancel = c
    		})
    		return {
    			token,
    			cancel	
    		}
    	}
    }
    
    //在xhr中加入代码
    const { cancelToken } = config
    if (cancelToken) {
    	cancelToken.promise.then(reason => {
    		request.abort()
    		reject(reason)	
    	})	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    7 防御CSRF

    axios.get('',{
    	xsrfCookieName: 'XSRF-TOKEN',
    	xsrfHeaderName: 'X-XSRF-TOKEN',
    })
    
    • 1
    • 2
    • 3
    • 4
  • 相关阅读:
    OpenCV 基础图像处理
    ThingsBoard Edge 安装部署(Docker)
    力扣每日练习3.14
    基于预训练模型的多标签专利分类研究
    Item-Based Recommendations with Hadoop
    QT-界面控件学习笔记
    【老生谈算法】matlab实现LMMSE算法信道均衡源码——LMMSE算法
    Nginx中对红黑树的使用
    初识 Jenkins 持续集成
    【竞技宝】DOTA2-梦幻联赛S22:AR命悬一线 XG确定晋级淘汰赛
  • 原文地址:https://blog.csdn.net/weixin_44208404/article/details/132620487