最近看了下 JavaScript 中的代理模式,私认为代理模式就是给被代理的对象做了一些访问控制相关的操作。这里的被代理的 “对象” 并不是严格意义上的对象,它可以是任何东西,包括语言层面的变量、对象、函数,甚至是业务问题,总之是一些你想隐藏在后面的东西,先让代理在前面把把关。
举个例子,项目中可能会有一些打点的需求,即上报数据,记录一些用户的操作。每次上报都会发送一个请求,如果上报的频率较高,上报的内容较多,可能就会占用较多的网络资源,影响正常的业务请求。因此我们需要实现一个功能,限制请求的频率,以及请求的数据大小,实现如下:
// 上报逻辑
function send(ids) {
console.log(`发送请求: ${ids}`);
}
// 使用代理模式后的上报函数
const report = (function(limit) {
let timer = null;
let cache = [];
// 负责调度真正的上报函数
const helper = () => {
if (timer) return;
// 2s 上报一次
timer = setTimeout(() => {
// 从数组中提取前十个
const ids = cache.splice(0, 10).join(",");
send(ids);
clearTimeout(timer);
timer = null;
// 如果还有任务,则继续执行
if (cache.length > 0) {
helper();
}
}, 2000);
}
return function(id) {
// 每次都往队列里面追加要上报的数据
cache.push(id);
// 使用 helper 函数调度执行
helper();
}
})(10); // 一次上报 10 个对象
// 模拟页面上调用了多次 report,但两秒后才真正往后端请求一次
for (let i = 1; i <= 78; i++) {
report(i);
}
注意,代理对象并不会影响到原对象,如果不想使用代理,那么完全可以使用原对象,因此二者最好对外暴露同样的接口,这样方便互相替换。代理模式也符合开放封闭原则,它并没有修改原对象的逻辑,但给原对象添加了新的行为。
你可能会问,这种操作不是很常见么,这就是代理模式?是的,很多时候我们就在不知不觉中使用过一些类似的解决方案,所以模式的应用不要死记硬背,不要生搬硬套,适合自己的才是最好的。