JS设计模式--代理模式

保护代理与虚拟代理

代理B可以帮助A过滤掉一些请求,这种代理叫做保护代理。一些操作交给代码B去执行,代理B会在时候的时候交给A,这是代理的另一种形式,虚拟代理。虚拟代理把一些开销很大的对象,延迟到真正需要他的时候才去创建。

保护代理用于控制不同权限的对象对目标的访问,但在js并不容易实现保护代理,因为我们无法判断谁访问了某个对象。而虚拟代理是最常用的一种代理模式,这里主要研究虚拟代理。

虚拟代理实现图片预加载

在web开发中,图片预加载是一种常见的技术,如果直接给某个img标签节点设置src属性,由于图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。常见的做法事先用一张loading图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到img节点里,这种场景就很适合使用虚拟代理。

下面来是实现这个虚拟代理,首先创建一个普通的本体对象,这个对象负责往页面中创建一个img标签,并且提供一个对外的setSrc接口,外界调用这个接口,便可以给该img标签设置设置src属性:

var myImage = (function () {
            var imgNode = document.createElement('img');
            document.body.appendChild(imgNode);

            return {
                setSrc: function (src) {
                    imgNode.src = src;
                }
            }
        })();
        myImage.setSrc('');

现在开始引入代理对象proxyImage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的loading.gif来提示用户图片正在加载。代码如下:

var myImage = (function () {
            var imgNode = document.createElement('img');
            document.body.appendChild(imgNode);

            return {
                setSrc: function (src) {
                    imgNode.src = src;
                }
            }
        })();
        
        var proxyImage = (function () {
            var img = new Image;
            img.onload = function () {
                myImage.setSrc(this.src);
            };
            return {
                setSrc: function (src) {
                    myImage.setSrc('loading.gif');
                    img.src = src;
                }
            }
        })();
        
        proxyImage.setSrc('');
现在我们通过proxyImage间接的访问MyImage。 proxyImage控制了客户对MyImage的访问,并且在此过程中加入一些额外的操作,比如在真正的图片加载好之前,先把img节点的src设置为一张本地的loading图片。
代理的意义

实际上,我们需要的只是给imgj节点设置src,预加载图片只是一个锦上添花的功能。如果能把这个操作放在另一个对象里,自然是一个非常好的方法。于是代理的作用在这里就体现出来了,代理负责预加载图片,预加载的操作完成之后,把请求重新交给本体MyImage。纵观整个程序,我们并没有改变或者增加MyImage的接口,但是通过代理对象,实际上给系统添加了新的行为。这是符合开放-封闭原则的。给img节点设置src的图片预加载这两个功能被隔离在两个对象里,他们可以各自变化不影响对方。何况就算有天我们不再需要预加载,只需要改成请求本体而不是请求代理对象即可。

缓存代理

缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传进来的参数跟之前一致,则可以直接返回前面的运算结果。

一个小例子--计算乘积

先创建一个用于求乘积的函数:

var mult= function () {
            console.log('开始计算乘积');
            var a = 1;
            for ( var i = 0, l = arguments.length; i<l; i++) {
                a = a * arguments[i];
            }
            return a;
        };
        
        mult(2,3);
        mult(2,3,4);
现在加入缓存代理函数:

var proxyMult = (function () {
            var cache = {};
            return function () {
                var args = Array.prototype.join.call(arguments, ',');
                if (args in cache) {
                    return cache[args];
                }
                return cache[args] = mult.apply(this, arguments);
            }
        })();

        proxyMult(1,2,3,4);
        proxyMult(1,2,3,4);
当我们第二次调用proxyMult(1,2,3,4);时,本体mult函数并没有被计算,proxyMult直接返回了之前缓存好的计算结果。通过增加缓存代理的方式,mult函数可以继续专注于自身的职责--计算乘积,缓存的功能是由代理对象实现的。

缓存代理用于ajax异步请求数据

我们常常在项目中遇到分页的请求,同一页的数据理论上只需要去后台拉取一次,这些已经拉取到的数据在某个地方被缓存之后,下次再请求同一页时,便可以使用之前的数据。

显然这里也可以引入缓存代理,实现方式跟计算乘积的例子差不多,唯一不同的是,请求数据是异步操作,我们无法直接把计算结果放到代理对象的缓存中,而是需要通过回调的方式。自行实现。






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值