JS设计模式-代理模式
在前端的一些表格里,往往会有一些复选的批量操作,比如给用户批量赋予权限,由于涉及表格分页以及反复翻页的勾选重现,很多时候,都是点击复选框后就像后台发起请求,直接进行数据的持久化。但是这时候就有个问题了,只要我的手速足够快,这种向后台发起请求的频率是非常高的,而我作为LOL的黄金分段玩家,也有自信一秒钟点五个复选框,为此,我们需要一个代理来拦截一下这种高频操作。
首先我们模拟向后台发请求的方法,很简单:
function ajaxRes(id) {
console.log(`请求参数id为${id}`);
}
如果我模拟点击了五次:
proxyRes(1)
proxyRes(2)
proxyRes(3)
proxyRes(4)
proxyRes(5)
控制台会模拟发了五次请求:
请求参数id为1
请求参数id为2
请求参数id为3
请求参数id为4
请求参数id为5
为此我们希望在一定时间内的频繁操作会缓存起来,暂时不向后台请求。
所以代理函数如下:
function proxyRes() {
let timer = null;
let cache = []
return function(id) {
cache.push(id);
// 如果timer不为空,也就是还在两秒内,就直接返回。
if (timer) {
return
}
timer = setTimeout(() => {
// 向后台发请求
ajaxRes(cache);
// 清除计时
clearTimeout(timer);
timer = null;
// 清空缓存数组
cache.length = 0;
}, 2000);
}
}
我们利用函数的作用域,设定了timer
来记录操作时间,在第一次点击后的两秒内,都不会往后台发请求。而在这期间的操作,都放在了缓存cache
里,如此就会大大减轻服务器的压力。
const prox = proxyRes()
prox(1)
prox(2)
prox(3)
prox(4)
prox(5)
// 请求参数id为1,2,3,4,5
这回在控制台只会打印一条请求信息了。
在以往的操作中我们的流程是这样的
现在变成了
如果你看过我的其他文章,你会发现这和函数节流的结构非常像。你也可能会有疑问,我明明一个函数就能写完的东西,为什么非得拆成两个函数。因为我们代理函数的作用往往不会只代理这一个,上面的方法我们可以进一步改造:
function ajaxRes(id) {
console.log(`请求参数id为${id}`);
}
// 注意这里参数变成了一个函数
function proxyRes(fn) {
let timer = null;
let cache = []
return function(id) {
cache.push(id);
if (timer) {
return
}
// 这里执行了传入的函数
timer = setTimeout(() => {
fn(cache);
clearTimeout(timer);
timer = null;
cache.length = 0;
}, 2000);
}
}
// 使用的时候需要传入被代理的函数
const prox = proxyRes(ajaxRes)
prox(1)
prox(2)
prox(3)
prox(4)
prox(5)
这样其他的复选操作我们也可以一同代理了,我们也可以进一步理解代理的作用,就是为本体函数加一层缓存或者过滤。
在ES6
中有一个代理器对象Proxy
,通过它我们可以实现对一些对象属性的监控、过滤。
比如我们要监测一个对象的属性,一旦它发生了改变,就要执行一些操作。
// 定义一个对象
const obj = {now: '2020/01/01'}
// 设置代理对象pro,代理的就是第一个参数obj,这里监控的是setter
const pro = new Proxy(obj, {
// 第一个参数是目标对象,这里就是obj。第二个参数是对象的key。第三个是进行赋值操作时的新值
set: function(target, key, val){
// 如果值改变了,就会执行
console.log(`${key}被修改了,旧的的值为${target[key]},新的值是${val}`);
// 由于操作的是代理对象,真正要对obj进行赋值,需要下面的操作,其等同于target[key] = val。或者是Object.set
Reflect.set(target, key, val)
}
})
// 修改now的值,注意这里操作的是代理对象,而不是obj,操作obj并不会出发代理的监测
pro.now = new Date().toLocaleDateString()
一旦now
的值发生改变,控制台就会输出
now被修改了,旧的的值为2020/01/01,新的值是2021/9/9
有了Proxy
,我们就可以进一步的对对象内部属性进行校验、监控、监测了。