代理最简单的实现
var Flower = function () { };
var xiaoming = {
sendFlower (target) {
var flower = new Flower();
target.receiveFlower(flower)
}
}
// 代理对象
var B = {
receiveFlower (flower) {
// 代理对象帮目标对象过滤一些请求--保护代理
A.listenGoodMood(A.receiveFlower.bind(null, flower))
}
}
// 目标对象
var A = {
receiveFlower (flower) {
console.warn('收到了', flower)
},
listenGoodMood (fn) {
setTimeout(fn, 1200)
}
}
xiaoming.sendFlower(B);
保护代理和虚拟代理
保护代理
代理对象帮目标对象过滤一些请求.用于控制不同权限的对象对目标对象的访问
var B = {
receiveFlower (flower) {
// 代理对象帮目标对象过滤一些请求--保护代理
A.listenGoodMood(A.receiveFlower.bind(null, flower))
}
}
虚拟代理
虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建.
var B = {
receiveFlower (flower) {
A.listenGoodMood(() => {
let flower = new Flower();
A.receiveFlower(flower)
})
}
}
保护代理用于控制不同权限的对象对目标对象的访问,但在JavaScript并不容易实现保护代理,因为我们无法判断谁访问了某个对象。而虚拟代理是最常用的一种代理模式,本章主要讨论的也是虚拟代理。
虚拟代理实现图片预加载
var myImage = (function () {
var image = document.createElement('img');
document.body.appendChild(image);
return {
setSrc (src) {
image.setAttribute('src', src);
}
}
})();
var proxyDefaultMyImage = (function () {
var image = new Image();
image.onload = function (event) {
// 网络请求的开销大,为了用户体验,回调中更新UI
myImage.setSrc(this.src);
}
return {
setSrc (src) {
myImage.setSrc('../images/Snipaste_2020-10-25_21-14-55.png');
image.src = src;
}
}
})();
proxyDefaultMyImage.setSrc('https://placekitten.com/220/220')
代理和本体接口的一致性
上一节说到,如果有一天我们不再需要预加载,那么就不再需要代理对象,可以选择直接请求本体。其中关键是代理对象和本体都对外提供了setSrc方法,在客户看来,代理对象和本体是一致的,代理接手请求的过程对于用户来说是透明的,用户并不清楚代理和本体的区别,这样做有两个好处。
- 用户可以放心地请求代理,他只关心是否能得到想要的结果。
- 在任何使用本体的地方都可以替换成使用代理。
虚拟代理合并HTTP请求
var uploadFile = function (id) {
console.warn('需要上传的id是:' + id);
}
var proxyUploadFile = (function () {
var cache = [];
var timer = null;
return function (id) {
cache.push(id);
if (timer) {
return;
}
timer = setTimeout(() => {
uploadFile(cache);
clearTimeout(timer);
timer = null;
cache.length = 0;
}, 2000);
}
})();
for (i = 1; i <= 10; i++) {
document.querySelector('#a' + i).addEventListener('change', e => {
if (e.target.checked) {
proxyUploadFile(e.target.id)
}
})
}
缓存代理
缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果。
var mult = function () {
var result = 1;
for (var i = 0; i < arguments.length; i++) {
result *= arguments[i]
}
return result;
}
var proxyMult = (function () {
var cache = {};
return function () {
var arr = [].slice.apply(arguments);
var key = arr.join();
if (cache[key]) {
return cache[key];
} else {
return cache[key] = mult.apply(this, arr);
}
}
})();
用高阶函数动态创建代理
/**************** 计算乘积 *****************/
var mult = function () {
var a = 1;
for (var i = 0, l = arguments.length; i < l; i++) {
a = a * arguments[i];
}
return a;
};
/**************** 计算加和 *****************/
var plus = function () {
var a = 0;
for (var i = 0, l = arguments.length; i < l; i++) {
a = a + arguments[i];
}
return a;
};
var createProxyFactory = function (fn) {
var cache = {};
return function () {
var key = [].join.call(arguments);
if (cache[key]) {
return cache[key];
} else {
return cache[key] = fn.apply(this, arguments);
}
}
}
var proxyMult = createProxyFactory(mult),
proxyPlus = createProxyFactory(plus);
alert(proxyMult(1, 2, 3, 4)); // 输出:24
alert(proxyMult(1, 2, 3, 4)); // 输出:24
alert(proxyPlus(1, 2, 3, 4)); // 输出:10
alert(proxyPlus(1, 2, 3, 4)); // 输出:10