前端性能优化中的设计模式实践
性能优化的设计模式基础
设计模式在前端性能优化中扮演着关键角色,它们提供了经过验证的解决方案来处理常见性能瓶颈。理解这些模式如何与性能优化相结合,是构建高效Web应用的基础。
观察者模式是性能优化的核心模式之一。它通过解耦组件间的直接依赖,减少了不必要的渲染和计算:
class Observable {
constructor() {
this.observers = [];
}
subscribe(fn) {
this.observers.push(fn);
}
unsubscribe(fn) {
this.observers = this.observers.filter(observer => observer !== fn);
}
notify(data) {
this.observers.forEach(observer => observer(data));
}
}
// 使用示例
const resizeObservable = new Observable();
window.addEventListener('resize', () => {
resizeObservable.notify({
width: window.innerWidth,
height: window.innerHeight
});
});
懒加载与虚拟化模式
懒加载模式延迟非关键资源的加载,直到它们真正需要时才加载。这在处理大型列表或图像集合时特别有效:
class LazyLoader {
constructor(selector, options = {}) {
this.elements = document.querySelectorAll(selector);
this.threshold = options.threshold || 0;
this.init();
}
init() {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
this.loadContent(entry.target);
observer.unobserve(entry.target);
}
});
}, { threshold: this.threshold });
this.elements.forEach(el => observer.observe(el));
}
loadContent(element) {
const src = element.getAttribute('data-src');
if (src) {
element.src = src;
}
}
}
// 使用示例
new LazyLoader('img.lazy', { threshold: 0.1 });
虚拟滚动是另一种性能优化模式,它只渲染视窗内的元素:
class VirtualScroll {
constructor(container, itemHeight, totalItems, renderItem) {
this.container = container;
this.itemHeight = itemHeight;
this.totalItems = totalItems;
this.renderItem = renderItem;
this.visibleItems = Math.ceil(container.clientHeight / itemHeight);
this.startIndex = 0;
this.endIndex = this.startIndex + this.visibleItems;
this.init();
}
init() {
this.container.style.height = `${this.totalItems * this.itemHeight}px`;
this.content = document.createElement('div');
this.container.appendChild(this.content);
this.updateItems();
this.container.addEventListener('scroll', () => {
this.startIndex = Math.floor(this.container.scrollTop / this.itemHeight);
this.endIndex = Math.min(
this.startIndex + this.visibleItems,
this.totalItems
);
this.updateItems();
});
}
updateItems() {
const fragment = document.createDocumentFragment();
for (let i = this.startIndex; i < this.endIndex; i++) {
const item = document.createElement('div');
item.style.position = 'absolute';
item.style.top = `${i * this.itemHeight}px`;
item.style.height = `${this.itemHeight}px`;
this.renderItem(item, i);
fragment.appendChild(item);
}
this.content.innerHTML = '';
this.content.appendChild(fragment);
}
}
缓存与记忆化模式
缓存是提升性能的经典技术,而记忆化模式则是函数级别的缓存实现:
function memoize(fn) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn.apply(this, args);
cache.set(key, result);
return result;
};
}
// 使用示例
const expensiveCalculation = memoize((n) => {
console.log('Calculating...');
return n * n;
});
console.log(expensiveCalculation(5)); // 计算并缓存
console.log(expensiveCalculation(5)); // 从缓存读取
对于API请求,我们可以实现一个更复杂的缓存策略:
class ApiCache {
constructor(maxAge = 300000) { // 默认5分钟
this.cache = new Map();
this.maxAge = maxAge;
}
async get(url) {
const cached = this.cache.get(url);
const now = Date.now();
if (cached && now - cached.timestamp < this.maxAge) {
return cached.data;
}
const response = await fetch(url);
const data = await response.json();
this.cache.set(url, {
data,
timestamp: now
});
return data;
}
clear() {
this.cache.clear();
}
}
// 使用示例
const apiCache = new ApiCache();
apiCache.get('https://api.example.com/data')
.then(data => console.log(data));
节流与防抖模式
处理高频事件时,节流(throttle)和防抖(debounce)是必不可少的性能优化模式:
function throttle(fn, delay) {
let lastCall = 0;
return function(...args) {
const now = new Date().getTime();
if (now - lastCall < delay) return;
lastCall = now;
return fn.apply(this, args);
};
}
function debounce(fn, delay) {
let timeoutId;
return function(...args) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 使用示例
window.addEventListener('resize', throttle(() => {
console.log('Resize event throttled');
}, 200));
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(() => {
console.log('Search input debounced');
}, 300));
更高级的实现可以结合两者优点:
function adaptiveThrottle(fn, delay, options = {}) {
let lastCall = 0;
let timeoutId;
const { leading = true, trailing = true } = options;
return function(...args) {
const now = Date.now();
const remaining = delay - (now - lastCall);
if (remaining <= 0) {
if (leading) {
lastCall = now;
fn.apply(this, args);
}
clearTimeout(timeoutId);
} else if (trailing && !timeoutId) {
timeoutId = setTimeout(() => {
lastCall = Date.now();
timeoutId = null;
fn.apply(this, args);
}, remaining);
}
};
}
策略模式与性能优化
策略模式允许在运行时选择算法,这对于根据不同场景优化性能特别有用:
class SortStrategy {
constructor(strategy = 'default') {
this.strategies = {
default: array => array.slice().sort((a, b) => a - b),
quick: this.quickSort,
merge: this.mergeSort,
bubble: this.bubbleSort
};
this.setStrategy(strategy);
}
setStrategy(strategy) {
this.currentStrategy = this.strategies[strategy] || this.strategies.default;
}
sort(array) {
return this.currentStrategy(array);
}
quickSort(array) {
if (array.length <= 1) return array;
const pivot = array[0];
const left = [];
const right = [];
for (let i = 1; i < array.length; i++) {
if (array[i] < pivot) {
left.push(array[i]);
} else {
right.push(array[i]);
}
}
return [...this.quickSort(left), pivot, ...this.quickSort(right)];
}
// 其他排序算法实现...
}
// 使用示例
const sorter = new SortStrategy();
const smallArray = [3, 1, 4, 2];
sorter.setStrategy('bubble');
console.log(sorter.sort(smallArray));
const largeArray = Array.from({ length: 10000 }, () => Math.random());
sorter.setStrategy('quick');
console.log(sorter.sort(largeArray));
代理模式与性能优化
代理模式可以控制对对象的访问,实现延迟初始化、访问控制等优化:
class HeavyObject {
constructor() {
console.log('Creating heavy object...');
// 模拟耗时初始化
this.data = Array.from({ length: 1000000 }, (_, i) => i);
}
getItem(index) {
return this.data[index];
}
}
class HeavyObjectProxy {
constructor() {
this.realObject = null;
}
getItem(index) {
if (!this.realObject) {
this.realObject = new HeavyObject();
}
return this.realObject.getItem(index);
}
}
// 使用示例
const proxy = new HeavyObjectProxy();
console.log(proxy.getItem(100)); // 此时才会创建真实对象
对于图片加载,我们可以实现一个更智能的图片代理:
class ImageProxy {
constructor(placeholderSrc, realSrc) {
this.placeholder = new Image();
this.placeholder.src = placeholderSrc;
this.realSrc = realSrc;
this.realImage = null;
this.loaded = false;
}
loadRealImage() {
if (this.loaded) return Promise.resolve();
return new Promise((resolve) => {
this.realImage = new Image();
this.realImage.onload = () => {
this.loaded = true;
resolve();
};
this.realImage.src = this.realSrc;
});
}
display(element) {
element.appendChild(this.placeholder);
const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
this.loadRealImage().then(() => {
element.removeChild(this.placeholder);
element.appendChild(this.realImage);
});
observer.disconnect();
}
});
observer.observe(element);
}
}
享元模式与对象池
享元模式通过共享对象减少内存使用,特别适合大量相似对象的场景:
class FlyweightFactory {
constructor() {
this.flyweights = {};
}
getFlyweight(key) {
if (!this.flyweights[key]) {
this.flyweights[key] = new Flyweight(key);
}
return this.flyweights[key];
}
getCount() {
return Object.keys(this.flyweights).length;
}
}
class Flyweight {
constructor(intrinsicState) {
this.intrinsicState = intrinsicState;
}
operation(extrinsicState) {
console.log(`Intrinsic: ${this.intrinsicState}, Extrinsic: ${extrinsicState}`);
}
}
// 使用示例
const factory = new FlyweightFactory();
const flyweight1 = factory.getFlyweight('shared');
const flyweight2 = factory.getFlyweight('shared');
flyweight1.operation('state1');
flyweight2.operation('state2');
console.log(factory.getCount()); // 1
对象池模式管理对象生命周期,避免频繁创建销毁带来的性能开销:
class ObjectPool {
constructor(createFn, resetFn, size = 10) {
this.createFn = createFn;
this.resetFn = resetFn;
this.pool = [];
this.size = size;
this.initialize();
}
initialize() {
for (let i = 0; i < this.size; i++) {
this.pool.push(this.createFn());
}
}
acquire() {
if (this.pool.length > 0) {
return this.pool.pop();
}
console.log('Creating new object - pool exhausted');
return this.createFn();
}
release(obj) {
this.resetFn(obj);
this.pool.push(obj);
}
getPoolSize() {
return this.pool.length;
}
}
// 使用示例
const pool = new ObjectPool(
() => ({ id: Math.random().toString(36).substr(2, 9), used: false }),
obj => { obj.used = false; },
5
);
const objects = [];
for (let i = 0; i < 8; i++) {
const obj = pool.acquire();
obj.used = true;
objects.push(obj);
}
console.log('Pool size during use:', pool.getPoolSize());
objects.forEach(obj => pool.release(obj));
console.log('Pool size after release:', pool.getPoolSize());
命令模式与异步操作
命令模式封装操作,便于实现撤销、重做和异步操作队列:
class CommandManager {
constructor() {
this.history = [];
this.position = -1;
this.executing = false;
this.queue = [];
}
execute(command) {
if (this.executing) {
this.queue.push(command);
return;
}
this.executing = true;
command.execute().then(() => {
// 修剪历史记录到当前位置
this.history = this.history.slice(0, this.position + 1);
this.history.push(command);
this.position++;
this.executing = false;
if (this.queue.length > 0) {
this.execute(this.queue.shift());
}
});
}
undo() {
if (this.position >= 0) {
this.history[this.position--].undo();
}
}
redo() {
if (this.position < this.history.length - 1) {
this.history[++this.position].execute();
}
}
}
class AsyncCommand {
constructor(executeFn, undoFn) {
this.executeFn = executeFn;
this.undoFn = undoFn;
}
execute() {
return new Promise((resolve) => {
setTimeout(() => {
this.executeFn();
resolve();
}, 1000);
});
}
undo() {
this.undoFn();
}
}
// 使用示例
const manager = new CommandManager();
const command1 = new AsyncCommand(
() => console.log('Executing command 1'),
() => console.log('Undoing command 1')
);
const command2 = new AsyncCommand(
() => console.log('Executing command 2'),
() => console.log('Undoing command 2')
);
manager.execute(command1);
manager.execute(command2);
setTimeout(() => {
manager.undo();
manager.undo();
manager.redo();
}, 3000);
状态模式与性能优化
状态模式通过改变对象内部状态来改变其行为,避免条件分支带来的性能开销:
class TrafficLight {
constructor() {
this.states = {
red: new RedState(this),
yellow: new YellowState(this),
green: new GreenState(this)
};
this.currentState = this.states.red;
}
changeState(state) {
this.currentState = this.states[state];
this.currentState.activate();
}
show() {
return this.currentState.show();
}
next() {
this.currentState.next();
}
}
class LightState {
constructor(light, name) {
this.light = light;
this.name = name;
}
activate() {
console.log(`Activating ${this.name} light`);
}
show() {
return this.name;
}
}
class RedState extends LightState {
constructor(light) {
super(light, 'red');
}
next() {
this.light.changeState('green');
}
}
class GreenState extends LightState {
constructor(light) {
super(light, 'green');
}
next() {
this.light.changeState('yellow');
}
}
class YellowState extends LightState {
constructor(light) {
super(light, 'yellow');
}
next() {
this.light.changeState('red');
}
}
// 使用示例
const trafficLight = new TrafficLight();
console.log(trafficLight.show()); // red
trafficLight.next();
console.log(trafficLight.show()); // green
trafficLight.next();
console.log(trafficLight.show()); // yellow
组合模式与批量操作
组合模式允许统一处理单个对象和组合对象,优化批量操作性能:
class DOMComponent {
constructor(element) {
this.element = element;
this.children = [];
}
add(child) {
this.children.push(child);
}
remove(child) {
const index = this.children.indexOf(child);
if (index !== -1) {
this.children.splice(index, 1);
}
}
// 批量更新样式
updateStyle(styles) {
// 使用requestAnimationFrame优化批量DOM操作
requestAnimationFrame(() => {
this.applyStyleToSelf(styles);
this.children.forEach(child => child.updateStyle(styles));
});
}
applyStyleToSelf(styles) {
Object.assign(this.element.style, styles);
}
// 批量添加事件监听器
addEventListener(type, listener, options) {
this.element.addEventListener(type, listener, options);
this.children.forEach(child => child.addEventListener(type, listener, options));
}
}
// 使用示例
const container = new DOMComponent(document.getElementById('container'));
const header = new DOMComponent(document.createElement('div'));
const content = new DOMComponent(document.createElement('div'));
container.add(header);
container.add(content);
// 批量更新所有子元素的样式
container.updateStyle({
color: 'red',
fontSize: '16px'
});
// 批量添加事件监听
container.addEventListener('click', () => {
console.log('Clicked on container or child');
});
装饰器模式与性能监控
装饰器模式动态添加功能,非常适合实现非侵入式的性能监控:
function withPerformanceMetrics(fn, metricName) {
return function(...args) {
const start = performance.now();
const result = fn.apply(this, args);
const end = performance.now();
const duration = end - start;
console.log(`${metricName} took ${duration.toFixed(2)}ms`);
if (duration > 100) {
console.warn(`Performance warning: ${metricName} took too long`);
}
return result;
};
}
// 使用示例
class DataProcessor {
@withPerformanceMetrics
processLargeData(data) {
// 模拟耗时操作
let result = 0;
for (let i = 0; i < data.length; i++) {
result += data[i];
}
return result;
}
}
// 或者手动应用装饰
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
下一篇:前端测试中的设计模式运用