JavaScript代理模式

news2024/12/27 13:35:24

JavaScript代理模式

  • 1 什么是代理模式
  • 2 实现一个简单的代理模式
  • 3 保护代理和虚拟代理
  • 4 虚拟代理实现图片预加载
  • 5 虚拟代理合并HTTP请求
  • 6 缓存代理

1 什么是代理模式

代理模式是为一个对象提供一个代用品或占位符,以便控制对它的访问。

代理模式的关键是,当客户不方便直接访问一个对象或者不满足需要的时候,提供一个替身对象来控制对这个对象的访问,客户实际上访问的是替身对象,替身对象对请求做出一些处理之后,再把请求转交给本体对象。

2 实现一个简单的代理模式

举个例子,A与B是好朋友,但是有一天两人吵架了,于是A决定向B发消息道歉,这段行为用代码简单描述一下,如下所示:

var Message = function () {};

var A = {
  // 发送消息方法
  sendMessage: function (target) {
    var message = new Message();
    target.receiveMessage(message);
  },
};

var B = {
  // 接收消息方法
  receiveMessage: function (message) {
    console.log("收到消息:" + message);
  },
};

A.sendMessage(B);

但是,如果B拉黑了A,导致A无法通过发消息给B,只能通过两人的共同好友C来表达,这时A通过C来向B道歉,如下所示:

var Message = function () {};

var A = {
  // 发送消息方法
  sendMessage: function (target) {
    var message = new Message();
    target.receiveMessage(message);
  },
};

var C = {
  // C接收消息,并发送给B
  receiveMessage: function (message) {
    B.receiveMessage(message);
  },
};

var B = {
  // 接收消息方法
  receiveMessage: function (message) {
    console.log("收到消息:" + message);
  },
};

A.sendMessage(C);

如果C很了解B,B心情好的时候会与A和解,B心情不好的时候调解会失败,那么C可以通过监听B的心情变化来决定什么时候发消息给B,代码如下:

var Message = function () {};

var A = {
  // 发送消息方法
  sendMessage: function (target) {
    var message = new Message();
    target.receiveMessage(message);
  },
};

var C = {
  // 接收消息,并发送给B
  receiveMessage: function (message) {
    // 监听B的好心情,在心情好时发消息
    B.listenGoodMood(function () {
      B.receiveMessage(message);
    });
  },
};

var B = {
  // 接收消息方法
  receiveMessage: function (message) {
    console.log("收到消息:" + message);
  },
  // 监听心情变化方法
  listenGoodMood: function (fun) {
    // 假设1s之后心情变好
    setTimeout(() => {
      fun();
    }, 1000);
  },
};

A.sendMessage(C);

3 保护代理和虚拟代理

在上述例子中,代理C可以帮助B过滤掉一些消息,比如B不认识的人,或者B讨厌的人,这些消息在代理C中被过滤掉,这叫做保护代理

保护代理用于控制不同权限的对象对目标对象的访问,但在JavaScript并不容易实现保护代理,因为我们无法判断谁访问了某个对象。

C可以选择在B心情好的时候发送消息,使成功概率增加,这叫做虚拟代理。虚拟代理可以把一些开销很大的对象,延迟到真正需要它的时候才去创建。例如:

var C = {
  // 接收消息,并发送给B
  receiveMessage: function () {
    // 监听B的好心情,在心情好时发消息
    B.listenGoodMood(function () {
      var message = new Message();
      B.receiveMessage(message);
    });
  },
};

4 虚拟代理实现图片预加载

Web开发中,图片预加载是一种常用的技术,如果直接给某个img标签节点设置src属性,如果图片过大或者网络不佳,图片的位置往往有段时间会是一片空白。

常见的做法是先用一张loading图片占位,然后用异步的方式加载图片,等图片加载好了再把它填充到img节点里,这种场景就很适合使用虚拟代理。

下面我们来实现这个虚拟代理,首先创建一个普通的本体对象,这个对象负责往页面中创建一个img标签,并且提供一个对外的setSrc接口,外界调用这个接口,便可以给该img标签设置src属性:

var myImage = (function () {
  // 创建img标签
  var imgNode = document.createElement("img");
  document.body.appendChild(imgNode);
  return {
    setSrc: function (src) {
      // 设置图片src方法
      imgNode.src = src;
    },
  };
})();

myImage.setSrc("XXXXXXX");

如果我们把网速调慢,然后通过MyImage.setSrc给该img节点设置src,可以看到,在图片被加载好之前,页面中有一段长长的空白时间。
在这里插入图片描述
现在开始引入代理对象proxyImage,通过这个代理对象,在图片被真正加载好之前,页面中将出现一张占位的loading.gif, 来提示用户图片正在加载。代码如下:

var myImage = (function () {
  // 创建img标签
  var imgNode = document.createElement("img");
  document.body.appendChild(imgNode);
  return {
    setSrc: function (src) {
      // 设置图片src方法
      imgNode.src = src;
    },
  };
})();

// 代理对象,在图片加载好之前,放一张loading图片
var proxyImage = (function () {
  var img = new Image();
  img.onload = function () {
    myImage.setSrc(this.src);
  };
  return {
    setSrc: function (src) {
      myImage.setSrc("XXXXXXXXXX");
      img.src = src;
    },
  };
})();

proxyImage.setSrc("XXXXXXXXXX");

在这里插入图片描述

5 虚拟代理合并HTTP请求

例如以下场景,上学时每天都需要写作业,作业最后交给老师批阅,但是老师可能带了许多个班级,每个班级又有很多学生,如果老师亲自收作业,会浪费大量的时间,如果我们先把作业交给小组长,小组长再交给班长,由班长负责交给老师,这样可以节省很多工夫。

Web开发中,网络请求是很大的开销。假设我们在做一个文件同步的功能,当我们选中一个checkbox的时候,它对应的文件就会被同步到另外一台备用服务器上面:

<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
var synchronousFile = function (id) {
  console.log("开始同步文件,id 为: " + id);
};

var checkbox = document.getElementsByTagName("input"); // 获取所有的checkbox
for (var i = 0, c; (c = checkbox[i++]); ) {
  // 每点击checkbox一次,就发送一次文件
  c.onclick = function () {
    if (this.checked === true) {
      synchronousFile(this.id);
    }
  };
}

在这里插入图片描述
当我们选中4个checkbox的时候,依次往服务器发送了4次同步文件的请求。而点击一个checkbox并不是很复杂的操作,用户可以再很短的时间内快速进行checkbox的点击工作,由此可见,如此频繁的网络请求将会带来相当大的开销。

这时,我们可以通过一个代理函数proxySynchronousFile来收集一段时间之内的请求,最后一次性发送给服务器。比如等待2秒之后才把这2秒之内需要同步的文件ID打包发给服务器,如果不是对实时性要求非常高的系统,2 秒的延迟不会带来太大副作用,却能大大减轻服务器的压力。

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

var proxySynchronousFile = (function () {
  var cache = [], // 保存2s之内需要同步的文件id
    timer; // 定时器
  return function (id) {
    cache.push(id); // 推入id
    if (timer) return; // 如果定时器已经启动,不再执行下面的操作

    timer = setTimeout(() => {
      synchronousFile(cache.join(",")); // 向服务器发送文件
      clearTimeout(timer); // 清空定时器
      timer = null;
      cache.length = 0; // 清空id集合
    }, 2000);
  };
})();

var checkbox = document.getElementsByTagName("input"); // 获取所有的checkbox
for (var i = 0, c; (c = checkbox[i++]); ) {
  // 每点击checkbox一次,就发送一次文件
  c.onclick = function () {
    if (this.checked === true) {
      proxySynchronousFile(this.id);
    }
  };
}

在这里插入图片描述

6 缓存代理

缓存代理可以为一些开销大的运算结果提供暂时的存储,在下次运算时,如果传递进来的参数跟之前一致,则可以直接返回前面存储的运算结果。


例如:计算乘积,假设计算乘积是一个很复杂的运算

先创建一个计算乘积的函数:

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

mult( 2, 3 ); // 输出:6 
mult( 2, 3, 4 ); // 输出:24

现在加入缓存代理函数:

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

var proxyMult = (function () {
  let cache = {};
  return function () {
    let args = Array.prototype.join.call(arguments, ","); // 将参数用,拼接起来
    // 如果缓存中查到了这个参数,直接返回存好的值
    if (args in cache) {
      return cache[args];
    }
    // 如果没有查到缓存,将参数和值存在缓存中
    return (cache[args] = mult.apply(this, arguments));
  };
})();

proxyMult( 1, 2, 3, 4 ); // 输出:24 
proxyMult( 1, 2, 3, 4 ); // 输出:24

当我们第二次调用proxyMult( 1, 2, 3, 4 )的时候,mult函数并没有被计算,直接返回了之前缓存好的计算结果。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1038639.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

LCR 164.破解闯关密码(数字---字符)

目录 一、题目 二、解答 一、题目 LCR 164. 破解闯关密码 - 力扣&#xff08;LeetCode&#xff09; 二、解答 std::stoi 返回的是一个 int 类型的整数。std::stoull 返回的是一个 unsigned long long 类型的整数&#xff08;无符号长整数&#xff09; class Solution { pub…

unity gb28181 rtsp 视频孪生图像拉流和矫正插件(一)

目的是为了视频孪生&#xff0c;将视频放到三维里面&#xff0c;如果使用自己写的插件&#xff0c;有更好的灵活性&#xff0c;同时断线重连等等都更好控制了。 1、矫正算法和硬件解码 最好使用opencv制作&#xff0c;可以使用opencv的cuda加速&#xff0c;opencv的编译&…

【Ambari】银河麒麟V10 ARM64架构_安装Ambari2.7.6HDP3.3.1(HiDataPlus)

&#x1f341; 博主 "开着拖拉机回家"带您 Go to New World.✨&#x1f341; &#x1f984; 个人主页——&#x1f390;开着拖拉机回家_大数据运维-CSDN博客 &#x1f390;✨&#x1f341; &#x1fa81;&#x1f341; 希望本文能够给您带来一定的帮助&#x1f338;文…

图像练习-矩形4点OpenCV(01)

提取出里面最大矩形的四个顶点坐标 源图像 结果展示 代码 void getLine(std::vector<int>& data, int threshold) {for (int x 0; x < data.size(); x){if (0 data[x]){continue;}int maxValue 0, maxLoc -1, i -1;for (i x; i < data.size(); i){if …

普通货架智能改造

系统架构 普通货架亮灯改造 普通货架亮灯改造可以选用&#xff0c;铝合金多色灯条和电子标签&#xff0c;两种形式进行货架智能亮灯改造&#xff1b;其差别在于铝合金多色灯条亮灯改造后&#xff0c;只适用于手持终端扫描校验灭灯&#xff1b;电子标签则可以支持手动确认拍灭…

分布式运用之企业级日志ELFK+logstash的过滤模块

一、ELFK集群部署&#xff08;FilebeatELK&#xff09; 在搭建ELK的基础上安装Filebeat服务&#xff0c;Filebeat服务可以布置在以下任意一台主机&#xff0c;本次实验将布置在apache服务器的节点上 步骤一&#xff1a;安装 Filebeat&#xff08;在apache节点操作&#xff09…

渲染路径RenderingPath

文章目录 前言一、什么是渲染路径二、渲染路径有哪些1、前向渲染路径2、延迟渲染路径3、顶点照明渲染路径(已过时)4、旧的渲染路径&#xff08;已过时&#xff09; 前言 渲染路径RenderingPath 一、什么是渲染路径 为进行光照计算而设计的渲染方式 二、渲染路径有哪些 1、前向…

虹科案例 | ELPRO帮助客户实现符合GDP标准的温度监测和高效的温度数据管理

文章来源&#xff1a;虹科环境监测技术 点击阅读原文&#xff1a;https://mp.weixin.qq.com/s/wwIPx_GK3ywqWr5BABC4KQ 在本案例研究中&#xff0c;虹科ELPRO帮助客户 ● 实施了温度监测解决方案&#xff0c;以一致的数据结构获取各国和各种运输方式的数据; ● 通过将温度数据上…

华为OD机试 - 快递运输 - 送分题(Java 2023 B卷 100分)

目录 专栏导读一、题目描述二、输入描述三、输出描述四、解题思路1、题目描述2、大白话分析 五、Java算法源码六、效果展示1、输入2、输出3、说明 华为OD机试 2023B卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题…

邓俊辉《数据结构》→ “2.6.5 二分查找(版本A)”之“成功查找长度”递推式推导

【问题描述】 邓俊辉的《数据结构&#xff08;C语言版&#xff09;&#xff08;第3版&#xff09;》&#xff08;ISBN&#xff1a;9787302330646&#xff09;中&#xff0c;开始于第48页的“2.6.5 二分查找&#xff08;版本A&#xff09;”内容在第50页详述了“成功查找长度”的…

敏捷在建设项目中的应用

敏捷这个概念天然地和软件开发密不可分&#xff0c;因为在2001年由17位软件业的管理大师聚在一起举办一场具有历史里程碑意义的大会&#xff0c;确定了敏捷软件开发宣言和敏捷原则&#xff0c;软件开发就是敏捷的起源之地。 钱亮老师在ShineScrum捷行举办的第五届敏捷论坛&…

vue项目打包部署到服务器,报错。

这个是因为后端部署服务器时&#xff0c;名称没有对上&#xff0c;不是前端的问题&#xff0c;后端配置名称和前端的包名称保持一致就可以了。

pve虚拟lxc安装docker教程

目录 &#xff08;一&#xff09;前提1. 存在的问题2. 解决办法 &#xff08;二&#xff09;安装lxc系统1. 环境2. 镜像3. 安装流程 &#xff08;三&#xff09;ubuntu安装docker1. 不同版本docker介绍&#xff1a;2. 安装docker-ce3. 安装青龙4. 青龙的卸载更新 &#xff08;四…

9.23统计学金融学(第一部分)

泊松分布 某事件在特定时间或空间中发生的次数。比如一天内中奖的个数&#xff0c;一个月内某机器损坏的次数等。 泊松概率的成立条件是在任意两个长度相等的区间中&#xff0c;时间发生的概率是相同的&#xff0c;并且事件是否发生都是相互独立的。 泊松概率既然表示事件在…

Python的安装教程(Windows)

简单理解就两个动作&#xff1a;安装python、安装PyCharm 我们要跟着做&#xff01;&#xff01;&#xff01; 编辑器和编译器 编辑器和编译器是两个不同的概念。编辑器是一种编写代码的工具&#xff0c;方便人对程序的操作和管理。常见的编辑器有文本编辑器、网页编辑器、源…

python回文素数

这能有1和本身整除的整数叫素数&#xff1b;如一个素数从左向右和从右向左是相同的数&#xff0c;则该素数为回文素数。编程求出2-1000内的所有回文素数。 源代码&#xff1a; def sushu(n): for i in range(2,n//21): if n%i 0: return False r…

PZ-3B-70E2A-10、PZ-6B-220E2A-20电控比例压力流量驱动泵放大器

PZ-2B-35E1A-11、PZ-2B-35E2A-11、PZ-2B-35E3A-11、PZ-2B-45E1A-11、PZ-2B-45E2A-11、PZ-2B-45E3A-11、PZ-3B-70E1A-10、PZ-3B-70E2A-10、PZ-3B-70E3A-10、PZ-4B-70E1A-10、PZ-4B-70E2A-10、PZ-4B-70E3A-10、PZ-5B-130E1A-10、PZ-5B-130E2A-10、PZ-5B-130E3A-10、PZ-6B-180E1A-…

MySQL数据库入门到精通5--进阶篇(视图/存储过程/触发器)

4.视图/存储过程/触发器 4.1 视图 4.1.1 介绍 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视 图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。 通俗的讲&#xff0c;视图只保存了…

windows系统将 CMD(命令提示符)添加到鼠标右键菜单

一、新建OpenCMDHere.reg文件 OpenCMDHere.reg Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\Directory\Background\shell\OpenCMDHere] "Open CMD Here" "Icon""C:\\WINDOWS\\system32\\cmd.exe"[HKEY_CLASSES_ROOT\Directory\Ba…

相机数据恢复!详细步骤解析(2023新版)

和朋友在外面旅游用相机拍了好多有意义的照片和视频&#xff0c;但是导入电脑后不知道是被我删除了还是什么原因&#xff0c;这些照片都不见了&#xff0c;请问有方法恢复吗&#xff1f;” 在数字摄影时代&#xff0c;我们依赖相机记录珍贵的瞬间。然而&#xff0c;相机数据丢失…