《JavaScript设计模式与开发实践》模式篇(3)—— 代理模式

3,062

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

故事背景:

假设当 A 在心情好的时候收到花,小明表白成功的几率有 60%,而当 A 在心情差的时候收到花,小明表白的成功率无限趋近于 0。 小明跟 A 刚刚认识两天,还无法辨别 A 什么时候心情好。如果不合时宜地把花送给 A,花 被直接扔掉的可能性很大,这束花可是小明吃了 7 天泡面换来的。 但是 A 的朋友 B 却很了解 A,所以小明只管把花交给 B,B 会监听 A 的心情变化,然后选 择 A 心情好的时候把花转交给 A

代码实现:

var Flower = function(){};
var xiaoming = {
    sendFlower: function( target){
        var flower = new Flower();
        target.receiveFlower( flower ); 
    }
};
var B = {
    receiveFlower: function( flower ){
        A.listenGoodMood(function(){ 
            var flower = new Flower(); 
            A.receiveFlower( flower );
        }); 
    }
};
var A = {
    receiveFlower: function( flower ){
        // 监听 A 的好心情
        console.log( '收到花 ' + flower ); 
    },
    listenGoodMood: function( fn ){
        setTimeout(function(){ // 假设 10 秒之后 A 的心情变好
            fn(); 
        }, 10000 );
    } 
};
xiaoming.sendFlower( B );

由上面的例子可以引出两种代理模式

  • 保护代理 代理 B 可以帮助 A 过滤掉一些请求,比如送花的人中年龄太大的或者没有宝马的,这种请求就可以直接在代理 B 处被拒绝掉
  • 虚拟代理 假设现实中的花价格不菲,导致在程序世界里,new Flower 也是一个代价昂贵的操作, 那么我们可以把 new Flower 的操作交给代理 B 去执行,代理 B 会选择在 A 心情好时再执行 new Flower

应用场景

  • 虚拟代理实现图片预加载
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( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' );
             img.src = src;  
        }
    } 
})();
proxyImage.setSrc('http://imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg' );
  • 虚拟代理合并HTTP请求 假设我们在做一个文件同步的功能,当我们选中一个 checkbox 的时候,它对应的文件就会被同 步到另外一台备用服务器上面。当一次选中过多时,会产生频繁的网络请求。将带来很大的开销。可以通过一个代理函数 proxySynchronousFile 来收集一段时间之内的请求, 最后一次性发送给服务器
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( ',' ) ); 
            clearTimeout( timer ); // 清空定时器 
            timer = null;
            cache.length = 0; // 清空 ID 集合
        }, 2000 ); 
    }// 2 秒后向本体发送需要同步的 ID 集合
})();

var checkbox = document.getElementsByTagName( 'input' );
   for ( var i = 0, c; c = checkbox[ i++ ]; ){
      c.onclick = function(){
      if ( this.checked === true ){
          proxySynchronousFile( this.id ); }
      }
};

系列文章:

《JavaScript设计模式与开发实践》最全知识点汇总大全