定义
一些类是受保护的,类上的方法不能直接被访问,需要设置一层代理,让中间的代理对象增加一些逻辑判断、调用前后执行一些操作,从而实现扩展目标的功能。
类图
代码示例
明星经纪人代理
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.clientHeight
function 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 = this
let 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。此为服务端反向代理的一种形式
代理模式和适配器模式、装饰器模式的区别
- 代理模式和适配器模式对比,适配器模式提供不同接口,代理模式提供一模一样的接口
- 代理模式和装饰器模式,装饰器模式原来的功能不变,还可以使用。代理模式改变了原来的功能。