代理模式
来源:互联网 发布:java 哈希表 编辑:程序博客网 时间:2024/06/05 20:32
写在前面
参考《JavaScript设计模式与实战》
代理模式
代理模式顾名思义就是为一个对象进行代理,对该对象的操作都会通过代理先去完成,达到为对象进行过滤保护等功能。
保护代理
通过代理,可以过滤掉一些不符合条件的操作,从而使得通过代理的那些操作可以操作对象。
虚拟代理
虚拟代理可以在真正需要某个东西的时候才去创建,这样可以减少不必要的开销。
应用:图片预加载
图片预加载
图片在开始被加载到加载结束的过程中可能会有一段较长的空白期,这样的体验并不好。如果在此过程中添加一个loading的动图,让用户知道图片正在加载,就可以提升用户体验。
通过代理实现
不实现预加载的效果是这样的
var myImg = (function(){ var imgNode = document.createElement('img'); document.body.append(imgNode); return { setSrc: function(src){ imgNode.src = src; } };})();myImg.setSrc('https://www.google.co.jp/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png');
现在,加上代理。代理实现的就是先设置图片的src为loading,一旦加载完成后,就改为正常的图片。
var myImg = (function(){ var imgNode = document.createElement('img'); document.body.append(imgNode); return { setSrc: function(src){ imgNode.src = src; } };})();var proxyImg = (function(){ var proxyImg = document.createElement('img'); proxyImg.onload = function() { myImg.setSrc(proxyImg.src); } return { setSrc: function(src) { proxyImg.src = src; myImg.setSrc('loading.png') } }})();proxyImg.setSrc('normal.png');
首先,代理会设置图片的src属性为loading图片,并创建一个新的img节点用于监听图片的onload事件。
书中有提到,不是用代理其实也可以实现(只需要在myImg多添加一个img节点监听onload时间即可)。
那为什么需要代理呢?
- 代理实现了JS中的单一职责原则,也就是说myImg处既然实现的职责是显示图片,那么再添加一个预加载图片的职责就成了多职责了。多职责的坏处体现在强耦合。
按道理来讲,图片的预加载只不过是锦上添花的一个效果。如果某一天我们不需要了,删除这个效果就需要操作myImg
对象。
也可以看到proxyImg
和myImg
拥有相同的方法,这也是有它的道理的。
- 代理和被代理的对象拥有相同的方法这一操作很好地实现了封装,也就是说,用户不会在意你内部是如何进行的代理,对他来说设置图片只需要调用
setSrc
即可。
如果有一天不需要预加载了,也只需要把方法的对象改为myImg
,不需要再去学习myImg
中设置图片的方法。
应用:合并HTTP请求
合并HTTP请求可以大大提高前端性能,合并HTTP请求可不仅仅在浏览器请求页面的时候。
在前些天我写了一个vue+express
的博客应用时,遇到过用户增删改链接的时候,我当时想的是如果每次操作都要去访问一次数据库,再加上频繁操作,不断去发送http请求将是一件多么大的开销。
于是我添加了一个按钮让用户自己去点击保存。实际上这并不合适。
看了这本书后,发现可以通过代理的方式进行保存操作。
- 将修改后的数据保存在数组中,每次用户操作后的结果都保存在数组中。这样,只需要在一段时间后,让代理发送http请求并发送数组中的数据进行保存即可。
既然这里提到了,我就使用这个设计模式进行修改一下。
大概的感觉如下
在我的项目中,代理的感觉可能比较不明显。主要是在state
中维护的links
作为存放数据的地方。
一旦点击添加按钮并成功添加,就会触发一个定时器,这个定时器会把5秒内的所有操作的最后结果提交上去,并清除定时器以便下次使用。
if(!this.timer) { this.timer = setTimeout(()=>{ this.saveLinks(this.links); clearTimeout(this.timer); this.timer = null; }, 5000);}
links
和timer
共同为代理,links
存放处理后的数据,timer
则定时将它们上传到服务器。
应用:惰性加载
书中还提到了代理在惰性加载中的应用。
惰性加载就是需要时再加载。作者举了一个控制台的例子,这个例子描述的是用户可以使用console.log(xxx)
来在控制台查看输出,但是前提是用户必须先打开了控制台。
如果用户在没有打开控制台的情况下执行了console.log
语句,那么就需要先保存语句,到控制到打开后执行。
代理是这样写的:
var cache = []; var miniConsole = { log: function(){ var args = arguments; cache.push( function(){ return miniConsole.log.apply( miniConsole, args ); }); } }; miniConsole.log(1);
监听用户按下F2
按钮:
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 ); } };// 监听用户按下F2document.body.addEventListener( 'keydown', handler, false );
真正的脚本文件:
miniConsole = { log: function(){ console.log(Array.prototype.join.call(arguments)); }}
应用:缓存代理
缓存代理大部分的使用场景是,在用户输入相同的参数时得到的都是一样的,那么这个时候就不需要再多执行一次只需要从缓存中取即可。
作者举了一个乘积的例子,如果多次参数相同就不需要重新计算乘积
var multi = function() { var result = 1; for(var i = 0; i < arguments.length; i++) { result = result * arguments[i]; } return result;}var proxyMulti = (function(){ var cache = {}; return function() { var args = Array.from(arguments).join(','); if(cache[args]) { alert('c') return cache[args]; } else { cache[args] = multi.apply(this, arguments); return cache[args]; } }})();console.log(proxyMulti(2,3)); // 6 计算console.log(proxyMulti(2,3)); // 6 缓存
通用版本
代理只关心缓存中是否存在,而不关心是哪一个操作的代理。
var proxyMulti = function(fn){ var cache = {}; return function() { var args = Array.from(arguments).join(','); if(cache[args]) { alert('c'); return cache[args]; } else { cache[args] = fn.apply(this, arguments); return cache[args]; } }}let multiProxy = proxyMulti(multi);console.log(multiProxy(2,3)); // 6 计算console.log(multiProxy(2,3)); // 6 缓存
- 代理模式--动态代理
- 代理模式-静态代理
- 代理模式-静态代理
- 代理模式 & 动态代理
- 代理模式--静态代理
- 代理模式--动态代理
- 代理模式(动态代理)
- 代理模式-动态代理
- 代理模式-动态代理
- 代理模式动态代理
- 代理模式-静态代理
- 代理模式-动态代理
- 代理模式 -动态代理
- 代理模式---动态代理
- 代理模式-动态代理
- 代理模式--静态代理
- 代理模式!
- 代理模式
- MySQL中的表中增加删除字段
- 打开sns AP侧log输出
- win7登录cent6.7 samba服务器失败问题解决
- 算法导论程序16--基数排序(Python)
- bl31 进入bl32的过程
- 代理模式
- 【工具类】-转换人民币大小金额
- MVCC原理探究及MySQL源码实现分析
- Spring+EhCache缓存实例
- 解决VS2013单元测试调用Oracle时出现32位兼容问题
- phpcms v9调用指定栏目名称、url、图片、描述、子栏目、文章
- 半是转载半是自己代码与总结
- hash map 的工作原理。转
- 移动端tab点解切换和滑动切换