代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。
实例一、图片懒加载
图片懒加载是指,图片的加载应该在页面全部加载完后,再去加载。这样能够提高加载的速度和网页的体验性。实际操作就是,将原来网页的src独立出来,将原来图片使用一个loading.gif代替,然后在js里面手动创建个img去加载这个src,当加载完后把src替换就可以了。
var myImage=(function(){
var imgNode=document.createEvent('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(){
myImage.setSrc('/images/loading.gif');
img.src = src;
}
}
})();
proxyImage.setSrc('real.jpg');
上面的代码,我们通过proxyImage间接的访问myImage。proxyImage控制了用户对myImage的访问,并且在此过程中加入一些额外的操作,比如在真正加载完图片之前,先把img的节点的src设置为一张本地的loading图片。
保护代理和虚拟代理
这其实很好理解,保护代理就是起到保护作用,用来过滤掉一下不必要的请求,将真正需要的递给本体。
虚拟代理和函数节流的思想是一样的,将用户对性能的rape的伤害降低到最低。就像送快递一样,一件一件的送,这个公司是不是傻~ 所以为了生存,快递公司会当物品积攒到一定程度后才会让快递哥骑着小电驴穿梭在神州大地上。
虚拟代理
上面的保护代理阐述了怎样去拒绝请求,而虚拟代理的原则是收集请求(来者不拒). 他的出发点和保护代理的是一样的,都是为了节省请求的开支。
比如: 一个在线的编辑器,他是怎样同步你的内容呢?不会是,你内容一改变就发送一起请求同步吧。这个想法显然不切实际。如果这样,我每天没事都会打开这个编辑器,把asfdsafdsafsad…在里面敲上几分钟。保证分分钟弄死他的服务器。所以一般,我们会使用虚拟代理来接受你的请求。
就算你手速再快,我就只能2s发一次。 但这只是一个比较简单的实例。如果大家感兴趣可以研究一下,作业部落这个编辑器,他这个markdown同步和体验交互式我迄今为止用过应该算最好的一个了吧~
缓存代理
这个应该是应用最多的一个代理方式了,这种方式能够真正解决运算时间问题,网络不畅问题,离线问题。
搬一个例子过来吧。
计算乘积问题
function fb(num){ //斐波那契函数,超级耗内存
if(num<=1){
return 1;
}
return num*fb(--num)
}
//缓存代理出场了
var cProxy = (function(){
var cache = {};
return function(num){
if(cache[num]){
console.log(`this is cache ${cache[num]}`);
return cache[num];
}
return cache[num] = fb(num);
}
})();
//测试
console.log(cProxy(4)); //24
cProxy(4); //"this is cache 24"
恩,完美。 我们知道阶乘是比较累的一个计算方法,如果某天你的leader需要你计算很多次fb(2000)。用户的电脑也吃不消啊,所以为了体验,缓存代理是你百分百女友,好好珍惜。
当然,缓存代理并不只有这一点用途,比如需要重复获取网页中大部分数据的时候,就可以考虑使用缓存代理。前端工作者,99.9999%的应该都会遇见分页的问题(请不要告诉我你的分页是同步方式). 当我们点击一个页面的时候,获取后台的数据,然后再由我恩渲染到页面上,这是这样一个流程。 首先,渲染流程可以复用,那数据的复用性该怎么做呢?
恩,猜到了吧,就是使用cache进行一个缓存,然后如果下次获取分页的页码一致的话,就可以直接使用该数据了。
//向后台发请求,获取当前页面的数据
// http.getPage(page);
var pageProxy = (function(){
var cache = {};
return function(fn){ //fn作为处理页码数据的函数
var pageData = cache[page];
if(pageData){
return fn(pageData); //返回制定页码的数据
}
http.getPage(page) //获取制定页码的数据
.then((data)=>{
cache[page] = data; //存放数据
fn(data);
})
}
})();
最后再说一句吧,由于代理写起来需要更多的逻辑和代码,如果你的产经没有什么需求的话,不用代理也是行得通的。还有就是,用不用代理和你原来的本体执行的业务逻辑是完全分开的,即,如果后期产经有什么需求,或者你对自己的代码不满意,重构的时候,再添加代理,这种方式也是很推荐的。