javascript设计模式之三——代理模式
来源:互联网 发布:网络感叹号怎么办 编辑:程序博客网 时间:2024/06/01 08:53
代理模式
代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理模式是比较有用途的一种模式,而且变种较多( 虚拟代理、远程代理、copy-on-write代理、保护代理、Cache代理、防火墙代理、同步代理、智能指引 ),应用场合覆盖从小结构到整个系统的大结构,我们也许有代理服务器等概念,代理概念可以解释为:在出发点到目的地之间有一道中间层,意为代理。
应用场景:
远程代理:也就是为了一个对象在不同的地址空间提供局部代表,这样可以隐藏一个对象存在于不同地址空间的事实,就像web service里的代理类一样。
虚拟代理:根据需要创建开销很大的对象,通过它来存放实例化需要很长时间的真实对象,比如浏览器的渲染的时候先显示问题,而图片可以慢慢显示(就是通过虚拟代理代替了真实的图片,此时虚拟代理保存了真实图片的路径和尺寸。
代码实现:
// 图片加载函数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/image1.jpg"); img.src = src; } }})();// 调用代理对象加载图片proxyImage.setSrc( "http://images/qq.jpg");
下面是代理模式实现多图片加载的例子:
<!DOCTYPE html><html><head> <meta charset="utf-8"></head><body><button id='btnLoadImg'>加载图片</button><br><div id='imgContainer'></div><br><script type='text/javascript' src="js/jquery.js"></script><script type='text/javascript'>//图片地址保存在imgSrcs中 var imgSrcs = [ 'http://www.carsceneuk.com/wp-content/uploads/2015/03/88y9989.jpg', 'http://mfiles.sohu.com/20130223/5ff_403b2e7a_7a1f_7f24_66eb_79e3f27d58cf_1.jpg', 'http://img1.imgtn.bdimg.com/it/u=2678963350,1378052193&fm=21&gp=0.jpg' ];//页面加载完后开始运行 按钮绑定点击事件,一张一张加载图片 $(document).ready(function(){ $('#btnLoadImg').bind('click', function(){ doLoadImgs(imgSrcs); }); }); //创建img标签 //这里用自执行函数加一个闭包,是为了可以创建多个id不同的img标签。 var createImgElement = (function(){ var index = 0; return function() { var eleImg = document.createElement('img'); eleImg.setAttribute('width', '200'); eleImg.setAttribute('heght', '150'); eleImg.setAttribute('id', 'img' + index++); return eleImg; }; })(); function loadImg(img, src) { img.src = src; } function createLoadImgProxy(){ var imgCache = new Image(); var dfd = $.Deferred(); var timeoutTimer; //开始加载超时监控,超时后进行reject操作 function beginTimeoutWatcher(){ timeoutTimer = setTimeout(function(){ dfd.reject('timeout'); }, 10000); } //结束加载超时监控 function endTimeoutWatcher(){ if(!timeoutTimer){ return; } clearTimeout(timeoutTimer); } //加载完成事件处理,加载完成后进行resolve操作 imgCache.onload = function(){ dfd.resolve(this.src); }; //加载终止事件处理,终止后进行reject操作 imgCache.onabort = function(){ dfd.reject("aborted"); }; //加载异常事件处理,异常后进行reject操作 imgCache.onerror = function(){ dfd.reject("error"); }; return function(eleImg, src){ dfd.always(function(){// alert('always end'); //加载完成或加载失败都要终止加载超时监控 endTimeoutWatcher(); }).done(function(src){// alert('done end'); //加载完成后,往图片元素上设置图片 loadImg(eleImg, src); }).fail(function(msg){// alert('fail end:' + msg); //加载失败后,往图片元素上设置失败图片 loadImg(eleImg, 'images/image1.jpg'); }); loadImg(eleImg, 'loading.gif'); imgCache.src = src; //开始进行超时加载监控 beginTimeoutWatcher(); return dfd.promise(); }; } //一张一张的连续加载图片 //参数: // srcs: 图片路径数组 function doLoadImgs(srcs){ var index = 0; (function loadOneByOne(){ //退出条件 if(!(s = srcs[index++])) { return; } var eleImg = createImgElement(); document.getElementById('imgContainer').appendChild(eleImg); //创建一个加载代理函数 var loadImgProxy = createLoadImgProxy(); //在当前图片加载或失败后,递归调用,加载下一张 loadImgProxy(eleImg, s).always(loadOneByOne); })(); }</script></body></html>
应用2:虚拟代理合并http请求
<!DOCTYPE html><html><head> <meta charset="utf-8"></head><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<script type='text/javascript' src="js/jquery.js"></script><script type='text/javascript'> 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; // 清空ID集合 },20000); } })(); var checkbox = document.getElementsByTagName( 'input' ); for ( var i = 0, c; c = checkbox[ i++ ]; ){ c.onclick = function(){ if ( this.checked === true ){ proxySynchronousFile( this.id ); } } };</script></body></html>
将Http请求收集一段时间,最后一次性发送给服务器,减少了频繁向服务器提出请求的次数,大大减轻了服务器的压力,改善了性能。
缓存代理:缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果。
代码实现:
在不使用缓存代理时,代码可能会这样写:
var mult = function(){var a = 1;for ( var i = 0, l = arguments.length; i < l; i++ ){a = a * arguments[i];}return a;};mult( 2, 3 ); // 输出:6mult( 2, 3, 4 ); // 输出:24
这样写虽然实现了基本的功能,但是存在的问题是:如果多次计算mult( 2, 3 )时,会多次调用该函数,增大了运算的开销,我们应该将第一次运算的结果保存,当第二次运算同样的数据时,应该直接返回存储的结果。
将上述代码用代理模式设计后,代码如下:
var mult = function(){ console.log( '开始计算乘积' ); var a = 1; for ( var i = 0, l = arguments.length; i < l; i++ ){ a = a * arguments[i]; } return a; }; 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 ); } })(); alert( proxyMult( 1, 2, 3, 4 ));alert( proxyMult( 1, 2, 3, 4 ));
用代理模式设计代码后,运行时,可以发现console.log( ‘开始计算乘积’ );只打印了一次,proxyMult( 1, 2, 3, 4 )的结果出现两次。第二次是从缓存中获得。
安全代理:用来控制真实对象访问时的权限,一般用于对象应该有不同的访问权限。
智能指引:只当调用真实的对象时,代理处理另外一些事情。例如C#里的垃圾回收,使用对象的时候会有引用次数,如果对象没有引用了,GC就可以回收它了。
防火墙代理:控制网络资源的访问,保护主题不让“坏人”接近。
代理模式种类很多,这里只介绍了javascript中运用较多的虚拟代理和缓存代理。
- javascript设计模式之三——代理模式
- JavaScript学习之设计模式->代理模式
- JavaScript设计模式之代理模式
- JavaScript中的设计模式之代理模式
- 设计模式之代理模式 (三)
- 设计模式之三静态代理模式
- JAVA设计模式之三:代理模式
- 设计模式之——代理模式
- 设计模式之——代理模式
- 设计模式之——代理模式
- 设计模式之— 代理模式
- 设计模式之——代理模式(静态代理)
- 设计模式之——代理模式(动态代理)
- 12-JavaScript设计模式——代理模式
- 【三】设计模式——代理模式(Proxy Pattern)
- 设计模式—代理模式
- 设计模式—代理模式
- 设计模式—代理模式
- spark的安装方法
- npio word导出嵌套table实际可以用方法,付效果图
- XP下识别大容量分区移动硬盘
- Largest Number
- 函数赋值给变量后,自身不能再调用
- javascript设计模式之三——代理模式
- 配置mysql5.5主从复制、半同步复制、主主复制
- POJ-3974 Palindrome(manacher算法)
- dos环境下执行dmp时显示乱码解决办法之一
- 导PagerSlidingTabStrip库实现导航栏
- 华为OJ 初级:公共字串计算
- HttpClient 之HttpContext
- mysql 整理 -- 索引
- Base64编码