JavaScript设计模式(代理模式)
- 2019 年 11 月 5 日
- 筆記
一、简单的单例模式:
1、未使用代理模式的情况:小明直接给女神送花
var Flower = function() {} var xiaoming = { sendFlower: function( target ){ var flower = new Flower(); target.receiveFlower( flower ); } }; var A = { receiveFlower: function( flower ){ console.log( '收到花 ' , flower ); } }; xiaoming.sendFlower( A );
2、使用简单的代理模式:小明
var Flower = function() {} var xiaoming = { sendFlower: function( target ){ var flower = new Flower(); target.receiveFlower( flower ); } }; var A = { receiveFlower: function( flower ){ console.log( '收到花 ' , flower ); } }; var B = { receiveFlower: function( flower ){ A.receiveFlower(flower) } } xiaoming.sendFlower( B );
二、保护代理和虚拟代理
虽然这只是个虚拟的例子,但我们可以从中找到两种代理模式的身影。代理 B 可以帮助 A 过滤掉一些请求,比如送花的人中年龄太大的或者没有宝马的,这种请求就可以直接在代理 B 处被拒绝掉。这种代理叫作保护代理。A 和 B 一个充当白脸,一个充当黑脸。白脸 A 继续保持 良好的女神形象,不希望直接拒绝任何人,于是找了黑脸 B 来控制对 A 的访问。
另外,假设现实中的花价格不菲,导致在程序世界里,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; } } })(); myImage.setSrc('http:// imgcache.qq.com/music/photo/k/000GGDys0yA0Nk.jpg');
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' );
<body> <input type="checkbox" id="1"></input>1 <input type="checkbox" id="2"></input>2 <input type="checkbox" id="3"></input>3 <input type="checkbox" id="4"></input>4 <input type="checkbox" id="5"></input>5 <input type="checkbox" id="6"></input>6 <input type="checkbox" id="7"></input>7 <input type="checkbox" id="8"></input>8 <input type="checkbox" id="9"></input>9 </body>
var synchronousFile = function( id ){ console.log( '开始同步文件,id 为: ' + id ); }; var checkbox = document.getElementsByTagName( 'input' ); for ( var i = 0, c; c = checkbox[ i++ ]; ){ c.onclick = function(){ if ( this.checked === true ){ synchronousFile( this.id ); } } };
解决方案是,我们可以通过一个代理函数 proxySynchronousFile 来收集一段时间之内的请求, 最后一次性发送给服务器。比如我们等待 2 秒之后才把这 2 秒之内需要同步的文件 ID 打包发给 服务器,如果不是对实时性要求非常高的系统,2 秒的延迟不会带来太大副作用,却能大大减轻 服务器的压力。:
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 ); } } }