zoukankan      html  css  js  c++  java
  • JavaScript设计模式与开发实践---读书笔记(6) 代理模式

    代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。

    代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象。替身对象对请求做出一些处理后,再把请求转交给本体对象。

    保护代理:代理B可以帮助代理A过滤掉一些请求,这种代理叫保护代理。

    虚拟代理:虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建。虚拟代理是最常用的一种代理模式。

    1.虚拟代理实现图片预加载

    图片预加载是一种常用技术。

    常见的做法是先用一张loading图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到img节点里,这种场景就很适合使用虚拟代理。

        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('images/1.jpg');//本地图片
                    img.src = src;
                }
            }
        })();
    
        proxyImage.setSrc('http://img04.sogoucdn.com/app/a/100520021/b173203599e22d825c5f905d1da92535');

    代理的意义:
    单一职责原则:就一个类(通常也包括对象和函数)而言,应该仅有一个引起它变化的原因。职责被定义为"引起变化的原因"。

    实际上,我们需要的只是给img节点设置src,预加载图片只是一个锦上添花的功能。于是代理的作用在这里就体现出来了,代理负责预加载图片,预加载的操作完成之后,把请求重新交给本体MyImage。

    代理和本体接口的一致性:

    上述代码,其中的关键是代理和本体都对外提供了setSrc方法,在客户看来,代理对象和本体是一致的,代理接手请求的过程对于用户来说是透明的,用户不清楚代理和本体的区别。

    这样有两个好处:

    1. 用户可以放心的请求代理,他只关心是否能得到想要的结果。
    2. 在任何使用本体的地方都可以替换成使用代理。

    另外,如果代理对象和本体都为一个函数(函数也是对象),函数必然都能被执行,则可以认为它们也具有一致的"接口",代码如下:

    var myImage = (function(){
            var imgNode = document.createElement('img');
            document.body.appendChild(imgNode);
    
            return {
                    imgNode.src = src;
            }
        })();
    
        var proxyImage = (function(){
            var img = new Image;
            img.onload = function(){
                myImage(this.src);
            }
            return function(src){
                    myImage.setSrc('images/1.jpg');//本地图片
                    img.src = src;
                }
        })();
    
        proxyImage.setSrc('http://img04.sogoucdn.com/app/a/100520021/b173203599e22d825c5f905d1da92535');


    2.虚拟代理合并HTTP请求

    在Web开发中,也许最大的开销就是网络请求。

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>虚拟代理合并http请求</title>
    </head>
    <body>
        <input type="checkbox" id="1">1
        <input type="checkbox" id="2">2
        <input type="checkbox" id="3">3
        <input type="checkbox" id="4">4
        <input type="checkbox" id="5">5
        <input type="checkbox" id="6">6
        <input type="checkbox" id="7">7
        <input type="checkbox" id="8">8
        <input type="checkbox" id="9">9
    </body>
    </html>
    <script>
        var synchronousFile = function(id){
            console.log('开始同步文件,id为:'+id);
        };
    
        var proxySynchronousFile = (function(){
            var cache = [],//保存一段时间需要同步的ID
                timer;//定时器
                return function (id){
                    cache.push(id);
                    if(timer){    //保证不会覆盖已经启动的定时器
                        return;
                    }
    
                    timer = setTimeout(function(){
                        synchronousFile(cache.join(','));//两秒后向本体发送需要同步的ID集合
                        clearTimeout(timer);    //清空定时器
                        timer = null;
                        cache.length = 0;//清空ID集合
                    },2000)
                }
        })();
        var checkbox = document.getElementByTagName('input');
        for(var i=0,c;c=checkbox[i++]; ){
            c.onclick = function(){
                if(this.checked === true){
                    proxysynchronousFile(this.id);
                }
            }
        };
    
    </script>

    3.虚拟代理在惰性加载中的应用

    4.缓存代理

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

    例子:1.计算乘积

       

        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时,本体mult函数并没有被计算,proxyMult直接返回了之前缓存好的计算结果

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

    5.用高阶函数动态创建代理

    可以为各种方法创建缓存代理。

    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 args = Array.prototype.join.call(arguments,',');
                if(args in cache){
                    return cache[args];
                }
                return cache[args] = fn.apply(this,arguments);
            }
        };
    
        var proxyMult = createProxyFactory(mult),
        proxyPlus = createProxyFactory(plus);
    
        alert(proxyMult(1,2,3,4));
        alert(proxyMult(1,2,3,4));
        alert(proxyPlus(1,2,3,4));
        alert(proxyPlus(1,2,3,4));

    6.其他代理模式

    • 防火墙代理:控制网络资源的访问。
    • 远程代理
    • 保护代理
    • 智能引用代理
    • 写时复制代理:通常用于复制一个庞大对象的情况。

    7. 小结

    JavaScript开发中最常用的是虚拟代理和缓存代理。

  • 相关阅读:
    vue使用腾讯地图选点组件问题总结
    腾讯位置服务实现点击建筑显示围栏及建筑信息效果
    unity使用UMP播放RTSP流,打包exe后显示空白
    uniapp获取context
    Android studio安装debug apk提示“调用者不被允许测试的测试程序”
    unity使用VuplexWebView内嵌浏览器遮挡前方按钮的问题
    unity透明材质上放3dtext不同角度,文字变灰的问题
    Python线程指南
    mysql 简单表和索引
    dubbo 提示 403 unknown user
  • 原文地址:https://www.cnblogs.com/6489c/p/5936855.html
Copyright © 2011-2022 走看看