从简单处理解代理模式(javascript)

138 阅读3分钟

本文档已更新于 【前端橘子君】 【Github】

代理模式就是不能直接访问某个对象时,使用另外一个对象来访问该本体对象

比如前端跨域,不能直接访问后端接口时,我们通过配置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仓库【前端橘子君】