代理模式
代理模式是为一个对象提供一个代用品或者占位符,以便控制对它的访问。关键之处是当客户不方便直接访问一个对象的时候,提供一个对象来控制对这个对象的访问,客户上访问的实际上是代理对象,代理对象对客户的请求作出部分处理后再把请求转发给真正要请求的对象。
代理分为虚拟代理和保护代理,虚拟代理会把一些开销很大的对象延迟到真正需要他的时候再去创建,JS中我们只讨论虚拟代理。代理和真正请求本体的接口要有一致性,这样对客户来说,访问代理和本体的话就是一致的,不需要考虑区别,只关心得到的返回结果和使用本体的地方都可以换成代理。
代理的意义,面向对象设计中,有一个单一职责原则,就是一个类(包括函数或者对象)来说,应该仅有一个引起它变化的原因,如果一个对象承担了多项职责,就会导致过高的耦合和低内聚。
虚拟代理实现图片的预加载
如果直接加载大的图片,图片位置一开始可能是一片空白常见的做法是先用一张清晰度低的loading图片占位,然后用异步的办法加载图片,加载好后再填充到原来的位置里。这个场景很适合虚拟代理,下面就来实现。
- 1 创建一个普通的本体对象,负责向页面中创建img标签,并提供对外的setSrc接口,外接调用接口可以给img设置src属性:
let myImage = (function () {
let imgNode = document.createElement('img');
document.body.appendChild(imgNode);
return {
setSrc: function (src) {
imgNode.src = src;
}
}
})();
myImage.setSrc('你要添加的img url') - 2 引入代理对象proxyImage,通过代理对象加载占位图除此之外书中还介绍了虚拟代理合并HTTP请求、在惰性加载中的应用;
let proxyImage = (function () {
let img = new Image;
img.onload = function () {
myImage.setSrc(this.src)
}
return {
setSrc: function (src) {
myImage.setSrc('你要添加的loading url')
img.src = src
}
}
})();
proxyImage.setSrc('你要添加的img url')缓存代理例子-计算乘积
缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时如果参数和之前一样,可以直接返回前面的结果。下面为简单示例: - 1 先创建用于求乘积的函数:
let mult = function () {
console.log('start 乘积计算');
let a = 1;
for (let i = 0, l = arguments.length; i < l; i++) {
a = a * arguments[i];
}
return a;
}
mult(2, 3) //6
mult(2, 3, 4) //24 - 2 缓存代理函数mult函数专注于计算乘积,代理对象实现缓存功能。
let proxyMult = (function () {
let cache = {};
return function () {
let args = Array.prototype.join.call(arguments, ',');
if (args in cache) { //如果传入的参数在cache中存在,直接返回
return cache[args];
}
return cache[args] = mult.apply(this, arguments); //把传入proxyMult的参数来计算乘积,结果加入缓存cache对象中
}
})();
proxyMult(2, 3, 4) //24
proxyMult(2, 3, 4) //24 这个第二次调用,参数一样,直接返回之前计算好的结果
同时,缓存代理可以用于ajax异步请求数据:项目中遇到分页的请求,同一页数据理论上只需要去后端请求一次,缓存渠道的数据,下次再请求同样的数据时候,可使用缓存数据。这里就可以引入缓存代理解决,但是实现的时候需要注意请求数据是异步操作。
总结
书中本章主要介绍了虚拟代理实现图片预加载、虚拟代理合并HTTP请求、在惰性加载中的应用以及缓存代理计算乘积、高级函数动态创建代理的例子(通过传入高级函数为各种计算创建缓存代理,将计算方法当作参数传入专门创建缓存代理的工厂里,这样可以为加减乘除创建代理,具体实现见书中本章)