代理模式
RoleTang 7/16/2022
# 代理模式
代理模式对于前端开发者或者常使用vue框架的人来说,并不陌生。
在ES6,提供了一个proxy
API,可以很好的做到代理,并且几乎是一切的代理。
代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
生活中很多代理的场景,比如明星等有经纪人作为代理等等。
例子,比如小明想追求小红,他可以直接将花送给小红。 但是比如小红是否会接受小明的花受心情的影响。但小明与小红并不熟悉,不能知道小红的心情是好是坏。同时小明的好朋友小白又是小红的好朋友,她可以很好的知道小红的心情,所以可以让小白帮小明送花,以此来提高小明成功的机率。代理模式在这种情况下便显示了作用。
代理模式的分类
保护代理 小白作为小红的代理人,帮她挑选花,同时小白可以帮小红过滤一些请求,比如那些年纪太大的中年人或者没有宝马的,这种就可以直接拒绝。保护代理用于控制不同权限的对象对目标对象的访问。
虚拟代理 上述小明让小白代他送花给小红的模式就是虚拟代理。虚拟代理可以把一些开销很大的对象,延迟到真正需要它的时候才去创建。
- 虚拟代理实现图片预加载
- 虚拟代理实现http请求的转发,比如连续一段时间发送多个请求可能会造成服务器的很大的压力,但是可以通过一个代理转发,它可以收集比如2s内的请求最后统一发出。
- 虚拟代理的惰性加载中的应用。可能有一个很大的js文件,他有很多功能,但最好不去一次性加载太大的文件。我们可以暴露一个与实际操作一样接口的代理对象(只有接口并不实现),用一个操作队列来缓存你需要的操作,当真正需要时再加载较大的js文件。
<script>
// 图片的预加载
// 创建一个 dom 对象去请求图片
// 之后监听它的加载进行图片的显示
// 同时可以添加加载中的 gif 作为显示
// 其实就下列预加载的实现而言,一个函数完全可以做到
// 但是为何需要使用到代理模式
// 是因为这更符合单一对象职责
// 一个进行src源的设置,一个进行预请求
const myImage = (function () {
const img = document.createElement('img')
document.body.appendChild(img)
return {
setImage(src) {
img.src = src
},
}
})()
// 代理真正的图片
const proxyImage = (function () {
// 创建另外一个图片对象,来监听图片源的加载
const img = new Image()
// 加载完成后实现显示
img.onload = function () {
myImage.setImage(this.src)
}
return {
setImage: function (src) {
img.src = src
myImage.setImage('一个加载中的图片...')
},
}
})()
</script>
// 缓存代理
const mul = (...args) => {
console.log('开始计算乘积')
return args.reduce((pre, cur) => {
return pre * cur
}, 1)
}
// 用闭包作缓存
const proxyMul = ((...args) => {
const cache = {}
const arg = args.join(',')
return function () {
if (cache[arg]) return cache[arg]
return (cache[arg] = mul(...args))
}
})()
// 开始计算乘积 只打印一次,代表只做了一次计算
console.log(proxyMul(1, 2, 3))
console.log(proxyMul(1, 2, 3))
// 其实下面的代码可以一个函数就解决
// 但终究是拆成了两个函数
// 这就是坚持符合设计模式的单一职责原则
// mul => 负责计算
// proxyMul => 负责缓存
// 那这样做的好处呢?
// 就是拆分了函数的耦合性,你甚至可以通过高阶函数创建不同的缓存
const mul = (...args) => {
console.log('开始计算乘积')
return args.reduce((pre, cur) => {
return pre * cur
}, 1)
}
const increment = (...args) => {
console.log('开始计算和')
return args.reduce((pre, cur) => {
return pre + cur
}, 1)
}
// 低耦合的好处!
const createProxyFactory = (fn) =>{
const cache = {}
return (...args) => {
const arg = args.join(',')
if (cache[arg]) return cache[arg]
return (cache[arg] = fn(...args))
}
}