代理模式
代理模式是对对象的代理,提供访问对象的权利,不直接访问对象,而是通过代理对象访问。代理分为保护代理和虚拟代理。保护代理就是为对象提供过滤机制。在Javascript中其实可以使用原生的Proxy实现。虚拟代理是将一些大的开销交给代理,达到惰性加载的目的。保护代理在Javascript不常见,着重记录虚拟代理
虚拟代理
虚拟代理就是将一些大的开销交给代理处理的过程。用常用的预加载技术举例,以下是没有使用代理的形式
const createImg = (function(){
const imgNode = document.createElement();
document.appendChild(imgNode);
return {
setSrc(src){
imgNode.src = src;
}
}
})()
接下来引入代理对象
const createImg = (function(){
const imgNode = document.createElement('img');
document.appendChild(imgNode);
return {
setSrc(src){
imgNode.src = src;
}
}
})()
// 将不变与变化分离开
const proxyCreateImg = function(){
const img = new Image();
img.onload = function(){
// 加载完毕后将请求极爱还给createImg
createImg.setSrc(this.src);
}
return {
setSrc(src){
createImg.setSrc('loading.img');
img.src = src;
}
}
}
添加代理对象对createImg进行代理,当图片加载完全将请求交还给createImg,在代理中进行消耗比较大的图片请求过程和loading。
为什么要使用代理对象
上述例子本身我们不使用代理对象也可以实现相同的效果
const createImg = (function(){
const imgNode = document.createElement('img');
document.body.appendChild(imgNode);
const img = new Image;
img.onload = function(){
imgNode.src = this.src;
}
return {
setSrc(src){
imgNode.src = 'loading.jpg';
img.src = src;
}
}
})()
如上。那为什么还要使用代理对象呢?在设计模式中需要时时刻刻注意那几条原则,不变与变化分离,开放-封闭原则、单一职责原则。。。假设以后我们不需要预加载了,那我们势必要深入代码内部,重新修改实现,代码中预加载部分与创建节点部分耦合,有两处变化的地方。但是使用代理对象可以做到分离的目的。如果做到接口一致,以后我们不需要使用预加载的时候就不使用,并不会有什么影响
缓存代理
某些重复的计算可以使用缓存代理的形式保存,下次获取时不进行重复的计算,假设有如下求和过程
function computedCount(){
let count = 0;
for(let i=0;i<arguments.length;i++){
count+=arguments[i];
}
return count;
}
const proxyComputedCount = (function(){
const caches = Object.create(null);
return function(){
const cache = Array.prototype.join.call(arguments,',');
if(cache in caches){
return caches[cache];
}
return caches[cache] = computedCount.apply(this,arguments);
}
})()
console.log(proxyComputedCount(1,2,3,4))
代理模式在ajax中的应用
缓存代理可以用于在重复的操作中,所以ajax同样道理,只是由于ajax异步的原因,需要在异步中获取
const axios = require('axios')
function getArticle(id,callback){
console.log('进来')
return axios.get(`http://jsonplaceholder.typicode.com/comments?postId=${id}`)
.then(results=>Promise.resolve(results.data));
}
const proxyGetArticle = (function(){
const caches = {};
return async function(id){
const cache = Array.prototype.join.call(arguments,',');
// console.log(caches)
if(cache in caches){
console.log('在里边')
return caches[cache];
}
await
getArticle(id).then(res=>{
console.log('获取')
Promise.resolve(caches[cache] = res)
})
// await
return caches[cache];
}
})()
async function getData(){
const start = Date.now()
const data= await proxyGetArticle(1)
const end = Date.now()
console.log(end-start)
const data1 = await proxyGetArticle(1)
console.log(Date.now()-end)
}
getData()
/*
进来
获取
2325
在里边
5
*/
何时使用代理
虽然使用代理模式非常方便,但是不需要时刻想着某个问题是否需要代理模式,当真正碰到不方便的时候,我们能马上想到这个方法。代理模式有非常多的情况,但是考虑到JavaScript的适用性,在JavaScript中使用最多的是虚拟代理和缓存代理