代理模式通过代理对象控制对原对象的访问,可实现虚拟代理和缓存代理;虚拟代理用于图片预加载,先显示占位图再替换真实图片;缓存代理用于函数结果缓存,避免重复计算提升性能;两者均能在不修改原逻辑的前提下增强功能与性能。
代理模式在JavaScript中是一种常见且实用的设计模式,它通过一个代理对象来控制对原对象的访问。这种模式能帮助我们延迟真实操作的执行(虚拟代理),或避免重复计算提升性能(缓存代理)。下面结合具体场景,说明如何用JavaScript实现虚拟代理和缓存代理。
在网页开发中,直接加载大图可能导致页面卡顿或白屏。虚拟代理可以在真实图片加载完成前,先展示占位图,等图片下载完毕再替换,从而优化用户体验。
实现思路
是创建一个代理对象,代替真实的图片对象进行加载管理。
代码示例:
function createImageProxy() {
const img = new Image();
const proxyImg = new Image();
proxyImg.src = 'loading.gif'; // 占位图
img.onload = function () {
proxyImg.src = img.src;
};
return {
setSrc(targetImg) {
proxyImg.src = 'loading.gif';
img.src = targetImg;
},
getElement() {
return proxyImg;
}
};
}
// 使用
const imageProxy = createImageProxy();
document.body.appendChild(imageProxy.getElement());
imageProxy.setSrc('real-image.jpg');
某些计算密集型函数可能被频繁调用,传入相同参数时反复计算浪费资源。缓存代理可以记录已计算的结果,下次请求相同参数时直接返回缓存值。
适用于递归计算、复杂数据处理等场景。
代码示例:
function createCacheProxy(fn) {
const cache = new Map();
return function (...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
console.log('命中缓存:', key);
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// 被代理的函数:斐波那契数列
function fibonacci(n) {
if (n <= 1) return n;
return fibonacci(n - 1) + fibonacci(n - 2);
}
const cachedFibonacci = createCacheProxy(fibonacci);
console.log(cachedFibonacci(10)); // 计算一次,后续调用直接取缓存
console.log(cachedFibonacci(10)); // 命中缓存
使用代理模式可以让原对象更专注自身职责,而将预加载、缓存、权限控制等横切逻辑交给代理处理。
虚拟代理适合资源加载类操作,比如图片、脚本、组件的懒加载;缓存代理适合开销大的纯函数调用。
现代JavaScript中的Proxy对象也能实现类似功能,但上述手动实现代理更直观,兼容性更好,适合理解原理和实际项目集成。
基本上就这些。掌握虚拟代理和缓存代理,能在不修改原逻辑的前提下增强功能和性能,是前端开发中值得掌握的技巧。