代理模式就是不能直接访问某个对象时,使用另外一个对象来访问该本体对象
比如前端跨域,不能直接访问后端接口时,我们通过配置nginx进行代理转发,从而达到解决跨域的问题。
代理常见的类型有保护代理模式、虚拟代理模式和缓存代理模式。
保护代理
阻止外部对内部变量、方法的直接访问或控制。
// 普通对象的修改及访问
var obj = {
name: '前端橘子君',
age: 15
};
obj.name = '前端';
console.log(obj.name); // 前端
我们知道,如上的obj对象,并没有对内部变量或方法进行控制,这样是极不安全的,如果我们想实现对其的保护,即保护其中的某些变量,我们就可以用保护代理模式了。
var objProxy = new Proxy(obj, {
set (target, key, value) {
if (key === 'name') return; // 不允许修改 name 变量
if (target[key] === value) return; // 如果旧值和新值相同,则直接返回
target[key] = value; // 修改值
}
})
objProxy.name = '前端';
objProxy.age = 20;
console.log(obj); // {name: '前端橘子君', age: 20}
就如上述例子,我们看到,使用代理模式就对目标对象进行了保护了,vue 中也使用了这种模式对数据进行保护,我们常用的this.name其实最终是通过代理转发到了vm._data中,有兴趣的可以去看看 vue 的源码。
虚拟代理
为提供性能,延迟本体执行,从而减少本体的执行次数。
通俗一点讲,虚拟代理就是在一定时间内控制目标对象的执行次数,项目中最常见的是节流和防抖的应用。
// 节流
function throttle(func, wait) {
let times = 0;
return function (...args) {
let nowDate = new Date();
if (nowDate - times > wait) {
func.apply(this, args);
times = nowDate;
}
}
}
var print = function () {
console.log('触发节流');
}
var t = throttle(print, 2000)
t();
t();
// 只会打印一次
在节流的例子中,print是本体,而throttle是代理,其代理的作用就是使打印函数print不会频繁触发,从而提升性能。
又比如,我们可以将部分请求的api进行优化,让其在非常短的时间内进行收集,然后通过一个批量查询的接口在适当时间进行触发,这样可以比相同时间内触发多次后端接口性能要好很多。
缓存代理
缓存代理就是为一定周期内不变的数据提供一个临时存储环境,从而对本体进行保护。
如果说虚拟代理是从时间上对性能进行优化,那么缓存代理就是从空间上进行优化。
最常见的一个例子是前端对数据的缓存了,比如token。
我们一般只会要求用户登录一次系统,然后将其token保存在本地,请求其他接口时不需要重新登陆,直接使用缓存的token就可以了,这就是最经典的缓存代理了。
服务器的数据就是本体,而本地存储的数据就是代理。
又比如单例模式,保证了内存中只有一个实例,减少了内存(即空间)上的花费。
优点
- 高扩展,如可以对某些数据进行保护
- 某些代理模式可以在时间/空间的花费上进行优化
缺点
- 某些代理模式可能会增加时间或空间的花费
- 代理模式需要额外的工作
更多相关文档,请见:
线上地址 【前端橘子君】
GitHub仓库【前端橘子君】