三、代理模式

小明要送花给小红,怕小红拒绝,小明把花交给小灯泡,小灯泡在小红心情好的时候将花送给小红,小灯泡就是代理。

保护代理

送花的人很多,小灯泡帮助小红过滤掉一些人,比如没有宝马的、年龄过大的。

小红可以保持女神形象不会直接拒绝任何人,小灯泡唱黑脸拒绝小红看不上的人。

虚拟代理

假设现实中的花价格不菲,导致在程序世界里,new Flower也是一个代价昂贵的操作。

那么我们可以把new Flower的操作交给代理小灯泡去执行,小灯泡会选择在小红心情好时再执行new Flower。

这是代理模式的另一种形式,叫作虚拟代理。

虚拟代理把一些开销很大的对象,延迟到真正需要它的时候才去创建

图片预加载

var myImg = (function () {
  var imgNode = document.createElement('img');
  document.body.appendChild(imgNode);
  return {
    setSrc: function (src) {
      imgNode.src = src;
    }
  };
})();

myImg.setSrc('https://img0.baidu.com/it/u=2237039644,3735368368&fm=26&fmt=auto');

上面的代码在图片被加载好之前,页面中有一段长长的空白时间。

引入代理对象proxyImage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的菊花图来提示用户图片正在加载。

var myImg = (function () {
  var imgNode = document.createElement('img');
  document.body.appendChild(imgNode);
  return {
    setSrc: function (src) {
      imgNode.src = src;
    }
  };
})();

// 代理对象
var proxyImg = (function () {
  var img = new Image();
  img.onload = function () {
    myImg.setSrc(this.src);
  };

  return {
    setSrc: async function (src) {
      myImg.setSrc('http://topurl.cn/98p'); // 本地菊花图
      img.src = await src();
    }
  };
})();

// 3秒后返回url,模拟图片加载时间
var imgUrl = function () {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('http://topurl.cn/98q');
    }, 3000);
  });
};

proxyImg.setSrc(imgUrl);

代理和本体接口的一致性

如果有一天我们不再需要预加载,那么就不再需要代理对象,可以选择直接请求本体。

其中关键是代理对象和本体都对外提供了setSrc方法,在客户看来,代理对象和本体是一致的,代理接手请求的过程对于用户来说是透明的,用户并不清楚代理和本体的区别,这样做有两个好处。

  • 用户可以放心地请求代理,他只关心是否能得到想要的结果。

  • 在任何使用本体的地方都可以替换成使用代理。

var myImg = (function () {
  var imgNode = document.createElement('img');
  document.body.appendChild(imgNode);
  
  return function (src) {  // 返回函数,二位对象的方法,myImg成为可执行的函数
    imgNode.src = src;
  };
})();

// 代理对象
var proxyImg = (function () {
  var img = new Image();
  img.onload = function () {
    myImg(this.src);
  };

  return async function (src) { // 返回函数,二位对象的方法,proxyImg成为可执行的函数
    myImg('http://topurl.cn/98p'); // 本地菊花图
    img.src = await src();
  };
})();

// 3秒后返回url,模拟图片加载时间
var imgUrl = function () {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve('http://topurl.cn/98q');
    }, 3000);
  });
};

proxyImg(imgUrl);

虚拟代理合并HTTP请求

假设页面中有100个checkbox,当选中时会发送请求。

如果选中一个就发送请求很占用服务器资源。

可以将2秒内选中项一起发送服务器,减少请求次数。

可以给“发送请求到服务器”做一个代理,“代理请求”的内容就是延迟2秒,将期间选中项一起给“发送请求到服务器

var synchronousFile = function (id) {
  console.log('开始同步文件,id为:' + id);
};

// 代理
var proxySynchronousFile = (function () {
  var cache = [];
  var timer = null;

  return function (id) {
    cache.push(id);

    if (timer) return;

    timer = setTimeout(function () {
      // 2秒后调用本体发送要同步的id
      synchronousFile(cache.join(','));
      cache.length = 0; // 清空缓存数组
      clearTimeout(timer); // 清空定时器
      timer = null;
    }, 2000);
  };
})();

var checkbox = document.getElementsByTagName('input');
Array.prototype.forEach.call(checkbox, function (item) {
  item.onclick = function () {
    if (this.checked === true) {
      proxySynchronousFile(this.id);
    }
  };
});

缓存代理

// 计算乘积,假装这个是非常好资源的操作
function mult() {
  return Array.prototype.reduce.call(
    arguments,
    (acc, cur) => {
      return acc * cur;
    },
    1
  );
}

/**
 * 代理函数
 * 每次调用mult之前,查看缓存里有没有
 * 有则返回缓存,没有则调用mult方法,并保存到缓存里
 */
var proxyMult = (function () {
  var cache = {};
  return function () {
    var args = Array.prototype.join.call(arguments, ',');
    if (args in cache) {
      console.log('返回缓存');
      return cache[args];
    }
    return (cache[args] = mult.apply(this, arguments));
  };
})();

console.log(proxyMult(2, 3, 4));
console.log(proxyMult(2, 3, 4));
console.log(proxyMult(2, 3, 4));

高阶函数动态创建代理

// 计算乘积,假装这个是非常好资源的操作
function mult() {
  return Array.prototype.reduce.call(
    arguments,
    (acc, cur) => {
      return acc * cur;
    },
    1
  );
}
// 计算加和
function plus() {
  return Array.prototype.reduce.call(
    arguments,
    (acc, cur) => {
      return acc + cur;
    },
    1
  );
}

function proxyFactory(fn) {
  var cache = {};
  return function () {
    var args = Array.prototype.join.call(arguments, ',');
    if (args in cache) {
      console.log('返回缓存');
      return cache[args];
    }
    return (cache[args] = fn.apply(this, arguments));
  };
}

var proxyMult = proxyFactory(mult);
var proxyPlus = proxyFactory(plus);

console.log(proxyMult(2, 3, 4));
console.log(proxyMult(2, 3, 4)); // 返回缓存

console.log(proxyPlus(2, 3, 4));
console.log(proxyPlus(2, 3, 4)); // 返回缓存

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值