代理模式
为一个对象提供一个代用品或占位符,以便控制对它的访问
(1)代理模式实现预加载
// 本体对象
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(‘http://help.leadsquared.com/wp-content/themes/help/images/Spinner_t.gif
’);
img.src = src;
}
}
})();
proxyImage.setSrc("http://img.zcool.cn/community/0117e2571b8b246ac72538120dd8a4.jpg@1280w_1l_2o_100sh.jpg"
);
现在通过proxyImage间接地访问myImage.proxyImage控制了客户对myImage的访问,并在此将入了其他的操作,比如在图片加载完成之前,先把img节点的src设置为一张gif的loading图片
在静态语言中,往往本体和代理都要有相同的接口,来保证它们会拥有相同的方法。但在javascript中,大多数情况下没有做类型检测,对于一门快速开发的脚本语言来说,这些影响都是可接受的。
把本体和代理对象都为一个函数,函数都能被执行,则认为它们有一致的接口。
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(‘http://help.leadsquared.com/wp-content/themes/help/images/Spinner_t.gif’) ;
img.src = src;
}
})();
proxyImage(‘http://img.zcool.cn/community/0117e2571b8b246ac72538120dd8a4.jpg@1280w_1l_2o_100sh.jpg’);
(2)虚拟代理合并http请求 假如有这样的一个需求,用户点击某个复选框要实时同步到另外一台服务器,如果没点击一次就要同步一次,那么对于服务器的压力无疑是巨大的,所以这个时候有;使用虚拟代理模式合并某段时间内需要同步的文件,这样对于减轻服务器的压力的效果是杠杠的。
<div id="app">
<input type='checkbox' id='1' />1
<input type='checkbox' id='2' />2
<input type='checkbox' id='3' />3
<input type='checkbox' id='4' />4
<input type='checkbox' id='5' />5
<input type='checkbox' id='6' />6
<input type='checkbox' id='7' />7
<input type='checkbox' id='8' />8
<input type='checkbox' id='9' />9
</div>
正文如下
var syncFiles = function(file) {
console.log(‘需要同步的文件,id为: ’, file);
}
var proxySyncFiles = (function() {
var timer, cache = [];
return function(file) {
cache.push(file);
if (timer) return; // 保证不会覆盖已经存在的定时器
timer = setTimeout(function() {
syncFiles(cache.join(‘,’));
clearTimeout(timer);
timer = null;
cache.length = 0;
}, 2000);
}
})();
var checkboxs = document.getElementByTagName(‘input’);
for (var i = 0, c;c=checkboxs[i++];) {
if (!this.checked) retrun;
c.onclick = function() {
proxySyncFiles(this.id);
};
}
(3)缓存代理 可以为一些开销大的运算结果提供暂时的存储,在下次进来的时候,如果传递进来的参数跟之前的一致,则可以直接返回前面存储的运算结果。
//计算乘积
var muti = function(){
var a = 1, args = arguments;
for(var i=0, len=arguments.length;i<len;i++){
a = a*args[i];
}
return a;
}
//已经计算过的结果,直接返回,无需重新计算
var proxyMuti = (function(){
var cache = {};
return function(){
var arg = Array.prototype.join.call(arguments);
if (arg in cache){
console.log('缓存数:', cache[arg]);
return cache[arg];
}
return cache[arg] = muti.apply(this, arguments);
}
})();
代理模式包括许多小分类,在 JavaScript 开发中最常用的是虚拟代理和缓存代理。虽然代理模式非常有用,但我们在编写业务代码的时候,往往不需要去预先猜测是否需要使用代理模式。 当真正发现不方便直接访问某个对象的时候,再编写代理也不迟。