代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。代理包含保护代理和虚拟代理,保护代理可以实现对访问对象的过滤,用于控制不同权限的对象对目标对象的访问,而虚拟代理则可以将一些开销比较大的对象放在真正需要时再去创建。
虚拟代理实现图片预加载
一定程度上可以理解为数据与表现分离的一种实践,即将图片渲染到页面的功能和下载图片的功能分开,图片下载好后改变显示的状态即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| var myImage = (function(){ var imgNode = document.createElement( 'img' ); document.body.appendChild( imgNode ); return function( src ){ imgNode.src = src; } })();
var proxyImage = (function(){ var img = new Image; img.onload = function(){ myImage( this.src ); } return function( src ){ myImage( 'file:// /C:/Users/svenzeng/Desktop/loading.gif' ); img.src = src; } })(); proxyImage( 'http:// imgcache.qq.com/music// N/k/000GGDys0yA0Nk.jpg' );
|
虚拟代理合并HTTP请求
当我们的操作可能产生高频次的HTTP请求时,为了减小对服务器的压力,我们应该将某些相同类型的高频次请求进行一定程度上的合并,比如收集一段时间内的请求信息和并进行发送。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| var synchronousFile = function( id ){ console.log( '开始同步文件,id 为: ' + id ); }; var proxySynchronousFile = (function(){ var cache = [], timer; return function( id ){ cache.push( id ); if ( timer ){ return; } timer = setTimeout(function(){ synchronousFile( cache.join( ',' ) ); clearTimeout( timer ); timer = null; cache.length = 0; }, 2000 ); } })(); var checkbox = document.getElementsByTagName( 'input' );
for ( var i = 0, c; c = checkbox[ i++ ]; ){ c.onclick = function(){ if( this.checked === true ){ proxySynchronousFile( this.id ); } } };
document.body.addEventListener("click",proxyClickHandle,false); function proxyClickHandle(){ var evtTarget = event.target||event.srcElement; if(evtTarget.nodeName==="INPUT"){ proxySynchronousFile(evtTarget.id); } }
|
虚拟代理在惰性加载中的应用
许多时候为了节省HTTP资源,我们会将某些实现特定功能的脚本或者资源在真正需要的时候才进行加载,此时我们可以将用户的操作进行缓存,同时加载脚本,待脚本加载完成后再从缓存队列中取出用户的操作依次执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| var miniConsole = (function(){ var cache = []; var handler = function( ev ){ if ( ev.keyCode === 113 ){ var script = document.createElement( 'script' ); script.onload = function(){ for ( var i = 0, fn; fn = cache[ i++ ]; ){ fn(); } }; script.src = 'miniConsole.js'; document.getElementsByTagName( 'head' )[0].appendChild( script ); document.body.removeEventListener( 'keydown', handler ); } }; document.body.addEventListener( 'keydown', handler, false ); return { log: function(){ var args = arguments; cache.push( function(){ return miniConsole.log.apply( miniConsole, args ); }); } } })(); miniConsole.log( 11 );
miniConsole = { log: function(){ console.log( Array.prototype.join.call( arguments ) ); } };
|
缓存代理
缓存代理可以为一些开销大的运算节省资源,尤其是在这些运算操作会进场重复的情况下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| 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 ) );
|
小结
虽然代理模式非常有用,但是模式的意义始终在于解决一类特定的问题,代理模式的使用场景其实比较明确,即不方便直接访问某个对象。只有在这样的情境下,才应当使用代理模式。