学习JavaScript设计模式之代理模式


Posted in Javascript onJanuary 12, 2016
  • 明星都有经纪人作为代理。如果请明星办一场商演,只能联系其经纪人,经纪人会把商演的细节和报酬谈好,再把合同交给明星签。

一、定义

代理模式:为一个对象提供一个代用品或占位符,以便控制对它的访问。
代理分为:保护代理和虚拟代理
保护代理:用于控制不同权限的对象对目标对象的访问,在JavaScript中很难判断谁访问了某个对象,所以保护代理很难实现。

二、图片预加载(最常见的虚拟代理应用场景)

图片预加载是一种常用技术,如果直接给某个img标签节点设置src属性,由于图片过大或者网络不佳,图片的位置往往有段时间会有空白。常见的做法事先用一张loading图片占位,然后异步加载图片,待图片加载完成,把其填充到img节点里。
实现原理:
创建一个Image对象:var a = new Image();
定义Image对象的src: a.src = “xxx.gif”;
这样做就相当于给浏览器缓存了一张图片。

可通过Image对象的complete属性来检测图像是否加载完成。每个Image对象都有一个complete属性,当图像处于装载过程中时,该属性值false,当发生了onload、onerror、onabort中任何一个事件后,则表示图像装载过程结束,此时complete属性为true。

(1)非代理实现

var myImage = (function() {
  var imgNode = document.createElement("img");
  document.body.appendChild(imgNode);
  var img = new Image();

  img.onload = function() {
    imgNode.src = img.src;
  };

  return {
    setSrc: function(src) {
      imgNode.src = "./images/loading.gif";
      img.src = src;
    }
  }
})();

myImage.setSrc("./images/originImg.png");

(2)代理实现

// 创建图片DOM
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);  // this指向img!img加载完成后,将img.src传递给myImage
  };

  return {
    setSrc: function(src) {
      myImage.setSrc("./images/loading.gif");   // loading
      img.src = src;
    }
  };
})();

proxyImage.setSrc("./images/originImg.png");

使用代理模式的好处:使每个函数功能单一,实现对象设计的“单一职责原则”!

三、文件同步

假设我们在做一个文件同步功能,当选中checkbox时候,它对应的文件就会被同步到另外一台服务器。

<body>
    <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
  </body>

没选中一个checkbox就同步一次,显然不太合理。因为在web开发中,最大的开销就是网络请求。
解决方案:通过一个代理函数来收集一段时间之内的请求,然后一次性发给服务器。

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

var proxySynchonousFile = (function() {
  var cache = [],   // 保存本次需要同步文件的id
    timer;     // 定时器

  return function(id) {
    cache.push(id);
    if(timer) { 
      // 不要覆盖已经启动的定时
      return;
    }

    timer = setTimeout(function(){
      synchronousFile(cache.join(","));
      clearTimeout(timer);
      timer = null;
      cache.length = 0;  // 清空缓存
    }, 2000);
  }
})();

var checkboxs = document.getElementsByTagName("input");

for(var i = 0, c; c = checkboxs[i]; i++) {
  c.onclick = function() {
    if(this.checked === true) {
      proxySynchonousFile(this.id);
    }
  }
}

四、缓存代理?计算乘积(序列一模一样)

var mult = function() {
  var result = 1;
  for(var i = 0, l = arguments.length; i < l; i++) {
    result= result * arguments[i];
  }
  return result;
};

var proxyMult = (function() {
  var cache = {};   // {"1,2,3": 6}
  return function() {
    var args = Array.prototype.join.call(arguments, ",");
    if(args in cache) {
      return cache[args];
    }
    return cache[args] = mult.apply(this, arguments);
  }
})();

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

// 改造:

var proxyFactory = function(fn) {
  var cache = {};
  return function() {
    var args = Array.prototype.join.call(arguments, ",");
    if(args in cache) {
      return cache[args];
    }
    return cache[args] = fn.apply(this, arguments);
  }  
};

console.log(proxyFactory(mult)(1, 2, 3));

希望本文所述对大家学习javascript程序设计有所帮助。

Javascript 相关文章推荐
很可爱的输入框
Aug 03 Javascript
javascript强大的日期函数代码分享
Sep 04 Javascript
JS中表单的使用小结
Jan 11 Javascript
js简单工厂模式用法实例
Jun 30 Javascript
javascript断点调试心得分享
Apr 23 Javascript
javascript代码调试之console.log 用法图文详解
Sep 30 Javascript
Vue.js组件间的循环引用方法示例
Dec 27 Javascript
vue父组件点击触发子组件事件的实例讲解
Feb 08 Javascript
vue中使用cookies和crypto-js实现记住密码和加密的方法
Oct 18 Javascript
使用pkg打包Node.js应用的方法步骤
Oct 19 Javascript
express+vue+mongodb+session 实现注册登录功能
Dec 06 Javascript
javascript设计模式 ? 建造者模式原理与应用实例分析
Apr 10 Javascript
基于JavaScript实现TAB标签效果
Jan 12 #Javascript
JavaScript实现瀑布流布局
Jun 28 #Javascript
轻松实现JavaScript图片切换
Jan 12 #Javascript
jQuery动画效果图片轮播特效
Jan 12 #Javascript
jQuery动画效果实现图片无缝连续滚动
Jan 12 #Javascript
jqueryMobile使用示例分享
Jan 12 #Javascript
WordPress中鼠标悬停显示和隐藏评论及引用按钮的实现
Jan 12 #Javascript
You might like
php函数array_merge用法一例(合并同类数组)
2013/02/03 PHP
php+mysqli批量查询多张表数据的方法
2015/01/29 PHP
PHP将二维数组某一个字段相同的数组合并起来的方法
2016/02/26 PHP
浅谈php中的循环while、do...while、for、foreach四种循环
2016/11/05 PHP
PHP面向对象程序设计OOP继承用法入门示例
2016/12/27 PHP
javascript 获取表单file全路径
2009/12/31 Javascript
js中匿名函数的N种写法
2010/09/08 Javascript
JavaScript.The.Good.Parts阅读笔记(二)作用域&amp;闭包&amp;减缓全局空间污染
2010/11/16 Javascript
JavaScript面向对象(极简主义法minimalist approach)
2012/07/17 Javascript
js正文内容高亮效果的实现方法
2013/06/30 Javascript
setTimeout自动触发一个js的方法
2014/01/15 Javascript
浅谈javascript中的闭包
2015/05/13 Javascript
jquery实现多条件筛选特效代码分享
2015/08/28 Javascript
Js apply方法详解
2017/02/16 Javascript
js实现移动端导航点击自动滑动效果
2017/07/18 Javascript
Angular中ng-repeat与ul li的多层嵌套重复问题
2017/07/24 Javascript
JavaScript上传文件时不用刷新页面方法总结(推荐)
2017/08/15 Javascript
vue中选项卡点击切换且能滑动切换功能的实现代码
2018/11/25 Javascript
[00:12]DAC2018 Miracle-站上中单舞台,他能否再写奇迹?
2018/04/06 DOTA
python实现simhash算法实例
2014/04/25 Python
Python selenium如何设置等待时间
2016/09/15 Python
Python入门_浅谈数据结构的4种基本类型
2017/05/16 Python
PyQt5 QSerialPort子线程操作的实现
2018/04/21 Python
浅析Python pandas模块输出每行中间省略号问题
2018/07/03 Python
python 3.6.4 安装配置方法图文教程
2018/09/18 Python
Python3.5运算符操作实例详解
2019/04/25 Python
Python + Requests + Unittest接口自动化测试实例分析
2019/12/12 Python
Python如何在DataFrame增加数值
2020/02/14 Python
Python TKinter如何自动关闭主窗口
2020/02/26 Python
使用opencv中匹配点对的坐标提取方式
2020/06/04 Python
Carmen Sol官网:购买果冻鞋、手袋和配件
2021/01/01 全球购物
2014年销售人员工作总结
2014/11/27 职场文书
贫困证明书范文
2015/06/16 职场文书
员工规章制度范本
2015/08/07 职场文书
2016猴年春节问候语
2015/11/11 职场文书
linux下导入、导出mysql数据库命令的实现方法
2021/05/26 MySQL