美文网首页程序员
JS设计模式之代理模式

JS设计模式之代理模式

作者: Splendid飞羽 | 来源:发表于2020-07-26 22:06 被阅读0次

    定义:

    为其他对象提供一种代理以控制对这个对象的访问。
    何时使用:想在访问一个类时做一些控制。

    如何解决:增加中间层。

    应用实例:
    1、明星使用经纪人做代理,请明星演出,只能联系他的经纪人,经纪人将所有演出细节和报酬谈妥之后,再将合同给明星签字。
    2、买火车票不一定在火车站买,也可以去代售点。
    如下图所示,就是在中间增加一个中间层做代理,例如es6的Proxy就是一个很好地例子

    image.png

    使用场景:
    按职责来划分,通常有以下使用场景:
    1、远程代理。
    2、虚拟代理。
    3、Copy-on-Write 代理。
    4、保护(Protect or Access)代理。
    5、缓存代理。
    6、防火墙(Firewall)代理。
    7、同步化(Synchronization)代理。
    8、智能引用(Smart Reference)代理。

    本文主要讲述的是js中常用的两种代理模式------> 虚拟代理和缓存代理

    1、我们先来看如何使用虚拟代理实现图片的懒加载
    //创建img对象,设置setSrc方法
    let myImg = {
        setSrc(imgNode, src){
            imgNode.src = src;
        }
    }
    //创建代理对象,处理真正的逻辑
    let ProxyImg = {
        setSrc(imgNode, src){
            myImg.setSrc(imgNode, 'file://image/loading.gif');
            let img = new Image();
            img.onload = () => {
                myImg.setSrc(imgNode, src);
            }
            img.src =  src;
        }
    }
    
    let imgNode = document.createElement('img');
    imgSrc = 'https://upload.jianshu.io/users/upload_avatars/1413261/a0f9887a-
    24f8-408c-bfd1-2975924e8f02.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/80/h/80/format/webp'
    document.body.appendChild(imgNode);
    ProxyImg.setSrc(imgNode, imgSrc);
    

    上面的代码比较粗糙的解释了代理模式的作用,下面进行代码的优化

    let myImg = (() =>{
        let imgNode = document.createElement('img');
        document.body.prepend(imgNode);
        return {
            setSrc(src){
                imgNode.src = src;
            }
        }
    })()
    
    let ProxyImg = ((src) => {
        let img = new Image();
        img.onload = () => {
            myImg.setSrc(img.src);
        }
        return {
            setSrc(src){
                myImg.setSrc('https://b-gold-cdn.xitu.io/v3/static/img/logo.a7995ad.svg');
                img.src =  src;
            }
        }
    })()
    
    imgSrc = 'https://upload.jianshu.io/users/upload_avatars/1413261/a0f9887a-
    24f8-408c-bfd1-2975924e8f02.jpg?imageMogr2/auto-orient/strip|imageView2/1/w/80/h/80/format/webp'
    ProxyImg.setSrc(imgSrc);
    
    案例小结

    可以看出代码优化之后,结构更加清晰。
    使用匿名函数自自执行,一方面可以不对外暴露接口与方法
    另一方面使得创建dom节点与加载进行异步分离,某种程度上实现代码的解耦。

    myImg对象负责创建dom节点,里面的setSrc负责渲染真正图片
    代理对象proxyImg负责创建img对象,设置初始图片路径src,等图片onload方法执行之后,便开始将传入的src替换初始图片的src,从而实现图片占位的效果。

    2、使用缓存代理实现计算结果的缓存
    // 计算乘积
    let mult = function(){
        let a = 1;
        for(let i = 0; i < arguments.length; i++){
            a = a * arguments[i];
        }
        console.log(a)
        return a;
    }
    // mult(1, 2);
    
    // 创建缓存代理的工厂
    let createProxyFactory = function(fn){
        let cache = {};
        return function(){
            let args = Array.prototype.join.call(arguments, ','); // '1,2,3,4'
            if(args in cache){
                return cache[args];
            }
            return cache[args] = fn.apply(this, arguments);
        }
    }
    let proxyMult = createProxyFactory(mult);
    proxyMult(1, 2, 3, 4);
    // 有了第一次cache对象中的缓存的结果,第二次直接返回
    proxyMult(1, 2, 3, 4);
    

    本次案例,第一次执行proxyMult的时候,返回一个function,当传入参数1234调用第一次的时候,缓存了一个计算记过{'1234', 24},当第二次传入同样的参数,便可以从cache对象中找到第一次的计算结果,直接返回即可,这样减少了计算。

    案例小结:通过传入高阶函数这种更加灵活的方式,可以为各种计算方法创建缓存代理。现在这些方法被当做参数传入一个专门用于创建缓存代理的工厂中,这样一来,我们就可以为乘法、加法、减法等创建缓存代理。

    大家可以思考一下缓存代理 如何用于ajax异步请求数据,同一页的数据理论上只需要去后台 领取一次,这些已经拉去到的数据在某个地方被缓存之后,下次再请求统同一页的时候,便可以直接使用之前的数据。

    参考曾参的《JavaScript设计模式与开发实践》

    相关文章

      网友评论

        本文标题:JS设计模式之代理模式

        本文链接:https://www.haomeiwen.com/subject/kxsglktx.html