代理最简单的实现
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) {// 网络请求的开销大,为了用户体验,回调中更新UImyImage.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)); // 输出:24alert(proxyMult(1, 2, 3, 4)); // 输出:24alert(proxyPlus(1, 2, 3, 4)); // 输出:10alert(proxyPlus(1, 2, 3, 4)); // 输出:10
