您现在的位置是:网站首页 > 代理模式(Proxy)的多种应用场景文章详情
代理模式(Proxy)的多种应用场景
陈川
【
JavaScript
】
42179人已围观
8701字
代理模式是一种结构型设计模式,通过创建一个代理对象来控制对原始对象的访问。它在JavaScript中有广泛的应用场景,从性能优化到安全控制,再到功能增强,都能看到代理模式的身影。
远程代理:访问远程资源
远程代理是最经典的代理模式应用之一,它为远程对象提供本地代表。在前端开发中,最常见的场景是与后端API交互。
class ApiProxy {
constructor(endpoint) {
this.endpoint = endpoint;
}
async getData() {
if (!this.cachedData) {
const response = await fetch(this.endpoint);
this.cachedData = await response.json();
}
return this.cachedData;
}
}
// 使用代理
const apiProxy = new ApiProxy('https://api.example.com/data');
apiProxy.getData().then(data => console.log(data));
这个代理实现了缓存功能,避免重复请求相同的API。它还隐藏了网络请求的复杂性,让客户端代码更简洁。
虚拟代理:延迟初始化
虚拟代理用于延迟创建开销较大的对象,直到真正需要时才进行初始化。这在处理大型对象或资源密集型操作时特别有用。
class HeavyImage {
constructor(src) {
this.src = src;
this.loadImage();
}
loadImage() {
console.log(`Loading heavy image from ${this.src}`);
// 实际加载图片的逻辑
}
display() {
console.log(`Displaying image from ${this.src}`);
}
}
class ImageProxy {
constructor(src) {
this.src = src;
this.realImage = null;
}
display() {
if (!this.realImage) {
this.realImage = new HeavyImage(this.src);
}
this.realImage.display();
}
}
// 使用代理
const imageProxy = new ImageProxy('large-image.jpg');
// 此时还没有真正加载图片
imageProxy.display(); // 第一次调用时才会加载
保护代理:访问控制
保护代理用于控制对原始对象的访问权限,常用于身份验证和授权场景。
class SensitiveData {
constructor() {
this.data = "Top Secret Information";
}
getData() {
return this.data;
}
}
class DataProxy {
constructor(user) {
this.realData = new SensitiveData();
this.user = user;
}
getData() {
if (this.user.isAdmin) {
return this.realData.getData();
} else {
throw new Error("Unauthorized access");
}
}
}
// 使用代理
const admin = { isAdmin: true };
const user = { isAdmin: false };
const adminProxy = new DataProxy(admin);
console.log(adminProxy.getData()); // 可以访问
const userProxy = new DataProxy(user);
try {
console.log(userProxy.getData()); // 抛出错误
} catch (e) {
console.error(e.message);
}
缓存代理:优化性能
缓存代理可以存储昂贵操作的结果,避免重复计算,显著提高性能。
class ExpensiveCalculation {
compute(input) {
console.log(`Performing expensive calculation for ${input}`);
// 模拟耗时计算
return input * input;
}
}
class CalculationProxy {
constructor() {
this.realCalculation = new ExpensiveCalculation();
this.cache = new Map();
}
compute(input) {
if (this.cache.has(input)) {
console.log(`Returning cached result for ${input}`);
return this.cache.get(input);
}
const result = this.realCalculation.compute(input);
this.cache.set(input, result);
return result;
}
}
// 使用代理
const proxy = new CalculationProxy();
console.log(proxy.compute(5)); // 执行计算
console.log(proxy.compute(5)); // 返回缓存结果
ES6 Proxy:元编程能力
JavaScript内置的Proxy对象提供了更强大的元编程能力,可以拦截和自定义基本操作。
const user = {
name: "John",
age: 30,
_password: "secret"
};
const userProxy = new Proxy(user, {
get(target, prop) {
if (prop.startsWith('_')) {
throw new Error("Access denied");
}
return target[prop];
},
set(target, prop, value) {
if (prop.startsWith('_')) {
throw new Error("Access denied");
}
target[prop] = value;
return true;
},
ownKeys(target) {
return Object.keys(target).filter(key => !key.startsWith('_'));
}
});
console.log(userProxy.name); // "John"
try {
console.log(userProxy._password); // 抛出错误
} catch (e) {
console.error(e.message);
}
console.log(Object.keys(userProxy)); // ["name", "age"]
日志代理:调试和监控
代理模式可以方便地添加日志功能,用于调试或监控对象的使用情况。
class Calculator {
add(a, b) {
return a + b;
}
subtract(a, b) {
return a - b;
}
}
function createLoggingProxy(target) {
return new Proxy(target, {
get(target, prop) {
if (typeof target[prop] === 'function') {
return function(...args) {
console.log(`Calling ${prop} with args: ${args}`);
const result = target[prop](...args);
console.log(`Result: ${result}`);
return result;
};
}
return target[prop];
}
});
}
const calculator = new Calculator();
const loggingCalculator = createLoggingProxy(calculator);
loggingCalculator.add(2, 3);
// 输出:
// Calling add with args: 2,3
// Result: 5
验证代理:输入校验
代理可以在方法调用前进行参数验证,确保输入符合要求。
class UserService {
createUser(name, age) {
return { id: Date.now(), name, age };
}
}
function createValidationProxy(target) {
return new Proxy(target, {
get(target, prop) {
if (typeof target[prop] === 'function') {
return function(...args) {
const [name, age] = args;
if (typeof name !== 'string' || name.length < 2) {
throw new Error("Name must be at least 2 characters long");
}
if (typeof age !== 'number' || age < 0 || age > 120) {
throw new Error("Age must be between 0 and 120");
}
return target[prop](...args);
};
}
return target[prop];
}
});
}
const userService = new UserService();
const validatedUserService = createValidationProxy(userService);
try {
validatedUserService.createUser("J", 25); // 抛出错误
} catch (e) {
console.error(e.message);
}
const user = validatedUserService.createUser("John", 30);
console.log(user); // 正常创建用户
组合代理:多重功能
实际应用中,我们经常需要组合多种代理功能,创建一个具有多种特性的代理对象。
class BankAccount {
constructor(balance = 0) {
this._balance = balance;
}
deposit(amount) {
this._balance += amount;
return this._balance;
}
withdraw(amount) {
if (amount > this._balance) {
throw new Error("Insufficient funds");
}
this._balance -= amount;
return this._balance;
}
get balance() {
return this._balance;
}
}
function createEnhancedProxy(target) {
return new Proxy(target, {
get(target, prop) {
// 保护私有属性
if (prop.startsWith('_')) {
throw new Error("Access denied");
}
const value = target[prop];
// 如果是方法,添加日志和验证
if (typeof value === 'function') {
return function(...args) {
console.log(`Calling ${prop} with args: ${args}`);
// 验证存款/取款金额
if (['deposit', 'withdraw'].includes(prop)) {
const [amount] = args;
if (typeof amount !== 'number' || amount <= 0) {
throw new Error("Amount must be a positive number");
}
}
const result = value.apply(target, args);
console.log(`Result: ${result}`);
return result;
};
}
return value;
}
});
}
const account = new BankAccount(100);
const secureAccount = createEnhancedProxy(account);
secureAccount.deposit(50); // 正常
try {
secureAccount.withdraw(-10); // 抛出错误
} catch (e) {
console.error(e.message);
}
try {
console.log(secureAccount._balance); // 抛出错误
} catch (e) {
console.error(e.message);
}
性能监控代理
代理模式可以用于监控方法的执行时间,帮助识别性能瓶颈。
class DataProcessor {
processLargeData(data) {
// 模拟耗时操作
for (let i = 0; i < 1000000000; i++) {}
return data.map(item => item * 2);
}
}
function createPerformanceProxy(target) {
return new Proxy(target, {
get(target, prop) {
const originalMethod = target[prop];
if (typeof originalMethod === 'function') {
return function(...args) {
const start = performance.now();
const result = originalMethod.apply(target, args);
const end = performance.now();
console.log(`${prop} executed in ${end - start} milliseconds`);
return result;
};
}
return originalMethod;
}
});
}
const processor = new DataProcessor();
const monitoredProcessor = createPerformanceProxy(processor);
const data = Array.from({ length: 100 }, (_, i) => i);
monitoredProcessor.processLargeData(data);
// 输出: processLargeData executed in X milliseconds
惰性加载代理
对于需要按需加载的资源,代理模式可以实现惰性加载策略。
class VideoPlayer {
constructor(videoId) {
this.videoId = videoId;
this.loadPlayer();
}
loadPlayer() {
console.log(`Loading heavy video player for video ${this.videoId}`);
// 实际加载视频播放器的逻辑
}
play() {
console.log(`Playing video ${this.videoId}`);
}
}
class LazyVideoPlayer {
constructor(videoId) {
this.videoId = videoId;
this.realPlayer = null;
}
play() {
if (!this.realPlayer) {
this.realPlayer = new VideoPlayer(this.videoId);
}
this.realPlayer.play();
}
}
// 使用代理
const lazyPlayer = new LazyVideoPlayer('video123');
// 此时还没有加载真正的播放器
lazyPlayer.play(); // 第一次调用时才会加载