定义
一些类是受保护的,类上的方法不能直接被访问,需要设置一层代理,让中间的代理对象增加一些逻辑判断、调用前后执行一些操作,从而实现扩展目标的功能。
类图

代码示例
明星经纪人代理
abstract class Star {abstract answerPhone(): void;}class YaoMing extends Star {available: boolean = true;answerPhone(): void {console.log("我是明星本人");}}class ProxyYaoMing extends Star {protected yao;constructor() {super();this.yao = new YaoMing();}answerPhone(): void {console.log("你好,我是明星的经纪人");if (this.yao.available) {this.yao.answerPhone();}}}let ym = new ProxyYaoMing();ym.answerPhone();
图片loading代理的示例
<style>.bg-container {width: 860px;height: 560px;}.bg-container img {width: 100%;height: 100%;}</style><body><div id="button-wrapper"><button data-src="image/1.png">image1</button><button data-src="image/2.png">image2</button><button data-src="image/3.png">image3</button></div><div class="bg-container"><img src="image/1.png" id="bg-image" alt=""></div><script>let btn = document.getElementById("button-wrapper")class bgImage {constructor() {this.imageSrc = document.getElementById("bg-image")}setSrc(src) {this.imageSrc.src = src}}class LoadingBackgroundImage {static Loading_url = "./image/loading.gif"constructor() {this.loadingImage = new bgImage()}setSrc(src) {this.loadingImage.setSrc(LoadingBackgroundImage.Loading_url)let img = new Image()img.onload = () => {this.loadingImage.setSrc(src)}img.src = src}}let bgimage = new bgImage()function setSrc(src) {let imageSrc = document.getElementById("bg-image")imageSrc.src = src}let loadingimage = new LoadingBackgroundImage()btn.addEventListener("click", (event) => {let src = event.target.dataset.src// console.log(src);// bgimage.setSrc(src)loadingimage.setSrc(src)})</script></body>
图片懒加载代理的示例
<style>.image {width: 400px;height: 320px;background-color: #ccc;}.image img {width: 100%;height: 100%;}</style><body><div class="container"><div class="image"><img data-src="/image/1.png"></div><div class="image"><img data-src="/image/2.png"></div><div class="image"><img data-src="/image/3.png"></div><div class="image"><img data-src="/image/4.png"></div><div class="image"><img data-src="/image/5.png"></div><div class="image"><img data-src="/image/6.png"></div><div class="image"><img data-src="/image/7.png"></div><div class="image"><img data-src="/image/8.png"></div><div class="image"><img data-src="/image/9.png"></div></div><script>let images = document.getElementsByTagName("img")let clientHeight = window.innerHeight || document.documentElement.clientHeightfunction lazyLoad() {for (let i = 0; i < images.length; i++) {if (images[i].getBoundingClientRect().top < clientHeight) {images[i].src = images[i].dataset.src}}}lazyLoad()window.addEventListener("scroll", lazyLoad)</script></body>
两个图片代理使用的服务
const express = require("express");const app = express();let path = require("path");app.get("/image/loading.gif", (req, res) => {res.sendFile(path.join(__dirname, "image", "loading.gif"));});app.get("/image/:name", (req, res) => {// console.log(req.path);setTimeout(() => {res.sendFile(path.join(__dirname, req.path));}, 2000);});app.get("/lazy", (req, res) => {res.sendFile(path.join(__dirname, "lazy.html"));});app.get("/", (req, res) => {res.sendFile(path.join(__dirname, "loading.html"));});app.listen(8000);
复杂计算的代理过程
使用缓存进行代理,减少重复计算
function factorial(num) {if (num == 1) {console.log("新计算的值...");return 1;} else {return num * factorial(num - 1);}}const proxy = function (fn) {const cache = {};return function (num) {if (num in cache) {return cache[num];}return (cache[num] = fn(num));};};let proxyFactorial = proxy(factorial);// console.log(factorial(5));// console.log(factorial(5));// console.log(factorial(5));console.log(proxyFactorial(5));console.log(proxyFactorial(5));console.log(proxyFactorial(5));
防抖节流的代理过程
防抖节流的定义
- 防抖:会开启多个定时器,在固定时间内,有新的事件进来就会销毁之前的定时器,然后重新创建一个定时器。
- 节流:只开启一个定时器,是在一个固定时间段执行事件,在此事件段内可多次执行,过了时间段就不执行。
防抖类似于现实中的黑车,来一个乘客开始倒计时5分钟后发车,又来一个乘客,司机重新计时,再次等一个5分钟。直到等5分钟周期内,都没有新乘客上车,才开始发车。
节流类似于现实中的出租车,来了一个乘客,司机问了目的,说等我喝口水一分钟后立马走,这个一分钟就是固定的定时器,不会再次开启新的定时器。
节流代码示例
<style>#container {width: 200px;height: 600px;overflow: scroll;border: 1px solid steelblue;}#container .content {height: 4000px;}</style><body><div id="container"><p>节流的实现</p><div class="content"></div></div><script>let container = document.getElementById("container")let lastTime = Date.now()function throttle(callback, interval) {let lastExecuteTime;return function () {let content = thislet args = Array.from(arguments)let now = Date.now()if (lastExecuteTime) {if (now - lastExecuteTime >= interval) {callback.apply(this, args)lastExecuteTime = now}} else {callback.apply(this, args)lastExecuteTime = now}}}const scrollEvent = (event) => {let nowDate = Date.now()console.log("触发了滚动事件", (nowDate - lastTime) / 1000);lastTime = nowDate}container.addEventListener("scroll", throttle(scrollEvent, 500))</script></body>
防抖的示例
<style>#container {width: 200px;height: 600px;overflow: scroll;border: 1px solid steelblue;}#container .content {height: 4000px;}</style><body><div id="container"><p>防抖的实现</p><div class="content"></div></div><script>let container = document.getElementById("container")let lastTime = Date.now()function debounce(callback, delay) {let timer;return function () {let args = Array.from(arguments)let now = Date.now()if (timer) {clearTimeout(timer)}timer = setTimeout(() => {callback.apply(this, args)}, delay)}}const scrollEvent = (event) => {let nowDate = Date.now()console.log("触发了滚动事件", (nowDate - lastTime) / 1000);lastTime = nowDate}container.addEventListener("scroll", debounce(scrollEvent, 500))</script></body>
如果一直滚动,滚动事件不会执行,只有在停止滚动了超过间隔事件0.5秒后才会执行滚动事件。
服务器的反向代理
首先创建一个8888服务器
let http = require("http");let httpProxy = require("http-proxy");const proxy = httpProxy.createProxyServer();const server = http.createServer((req, res) => {proxy.web(req, res, {target: "http://localhost:9999",});});server.listen(8888, () => console.log(8888));
创建一个9999服务器
let http = require("http");const server = http.createServer((req, res) => {res.write("9999");res.end();});server.listen(9999, () => console.log(9999));
访问localhost:8888服务器,页面内容显示9999。此为服务端反向代理的一种形式
代理模式和适配器模式、装饰器模式的区别
- 代理模式和适配器模式对比,适配器模式提供不同接口,代理模式提供一模一样的接口
- 代理模式和装饰器模式,装饰器模式原来的功能不变,还可以使用。代理模式改变了原来的功能。
