您现在的位置是:网站首页 > 前端性能优化中的设计模式实践文章详情

前端性能优化中的设计模式实践

性能优化的核心挑战

前端性能优化面临的核心矛盾在于功能丰富性与执行效率之间的平衡。随着Web应用复杂度提升,DOM操作频繁、资源加载阻塞、渲染计算耗时等问题逐渐显现。设计模式为解决这些问题提供了可复用的方案模板,通过合理的架构设计减少不必要的性能损耗。

单例模式优化资源管理

单例模式确保类只有一个实例,并提供一个全局访问点。在前端性能优化中,这特别适合管理共享资源:

class ResourceManager {
  constructor() {
    if (ResourceManager.instance) {
      return ResourceManager.instance;
    }
    this.cache = new Map();
    ResourceManager.instance = this;
  }

  getResource(url) {
    if (this.cache.has(url)) {
      return Promise.resolve(this.cache.get(url));
    }
    
    return fetch(url)
      .then(res => res.blob())
      .then(blob => {
        this.cache.set(url, blob);
        return blob;
      });
  }
}

// 使用示例
const manager1 = new ResourceManager();
const manager2 = new ResourceManager();
console.log(manager1 === manager2); // true

这种实现方式确保:

  1. 避免重复创建管理器实例
  2. 统一管理所有资源请求
  3. 实现内存缓存避免重复下载

享元模式处理大规模DOM

当页面需要渲染大量相似元素时,享元模式通过共享相同部分来减少内存占用:

class ListItemFlyweight {
  constructor(sharedStyle) {
    this.sharedStyle = sharedStyle;
  }

  render(uniqueContent) {
    const li = document.createElement('li');
    li.className = this.sharedStyle;
    li.textContent = uniqueContent;
    return li;
  }
}

// 使用示例
const listItemFactory = (() => {
  const flyweights = {};
  
  return {
    getFlyweight(style) {
      if (!flyweights[style]) {
        flyweights[style] = new ListItemFlyweight(style);
      }
      return flyweights[style];
    }
  };
})();

// 渲染1000个列表项
const container = document.getElementById('list-container');
for (let i = 0; i < 1000; i++) {
  const flyweight = listItemFactory.getFlyweight('list-item');
  container.appendChild(flyweight.render(`Item ${i}`));
}

关键优化点:

  • 样式类名只存储一次
  • 避免重复创建相同样式对象
  • 减少DOM操作的内存占用

观察者模式实现高效事件处理

传统的事件监听会导致大量回调函数堆积,观察者模式提供更精细的控制:

class EventObserver {
  constructor() {
    this.subscribers = new Map();
  }

  subscribe(eventType, callback) {
    if (!this.subscribers.has(eventType)) {
      this.subscribers.set(eventType, new Set());
    }
    this.subscribers.get(eventType).add(callback);
  }

  unsubscribe(eventType, callback) {
    if (this.subscribers.has(eventType)) {
      this.subscribers.get(eventType).delete(callback);
    }
  }

  publish(eventType, data) {
    if (this.subscribers.has(eventType)) {
      this.subscribers.get(eventType).forEach(cb => cb(data));
    }
  }
}

// 使用示例
const scrollObserver = new EventObserver();

// 组件A
scrollObserver.subscribe('scroll', pos => {
  console.log('Component A received:', pos);
});

// 组件B
scrollObserver.subscribe('scroll', pos => {
  console.log('Component B received:', pos);
});

// 触发滚动事件
window.addEventListener('scroll', () => {
  scrollObserver.publish('scroll', window.scrollY);
});

性能优势:

  1. 避免直接在window上绑定多个scroll事件
  2. 精确控制事件分发
  3. 简化事件注销管理

策略模式优化算法选择

根据不同场景选择最优算法策略:

const sortingStrategies = {
  smallDataset: arr => arr.sort((a, b) => a - b),
  largeDataset: arr => {
    // 使用更高效的大数据排序算法
    return quickSort(arr);
  },
  nearlySorted: arr => {
    // 对基本有序数据使用插入排序
    return insertionSort(arr);
  }
};

function sortData(data, strategyType) {
  const strategy = sortingStrategies[strategyType] || sortingStrategies.smallDataset;
  return strategy(data);
}

// 使用示例
const smallData = [5, 2, 8, 1];
const largeData = Array.from({length: 10000}, () => Math.random());

console.log(sortData(smallData, 'smallDataset'));
console.log(sortData(largeData, 'largeDataset'));

动态选择策略带来:

  • 避免单一算法应对所有场景
  • 根据数据特征自动选择最优解
  • 便于扩展新的处理策略

代理模式控制资源加载

通过代理对象控制对实际对象的访问:

class ImageProxy {
  constructor(targetUrl, placeholder) {
    this.targetUrl = targetUrl;
    this.placeholder = placeholder;
    this.realImage = null;
  }

  load() {
    if (!this.realImage) {
      this.realImage = new Image();
      this.realImage.src = this.targetUrl;
    }
    return this.realImage;
  }

  display() {
    if (this.realImage && this.realImage.complete) {
      return this.realImage;
    } else {
      const img = new Image();
      img.src = this.placeholder;
      return img;
    }
  }
}

// 使用示例
const gallery = document.getElementById('gallery');
const proxyImage = new ImageProxy(
  'large-image.jpg',
  'placeholder.jpg'
);

gallery.appendChild(proxyImage.display());

// 当需要时再加载真实图片
window.addEventListener('load', () => {
  gallery.replaceChild(
    proxyImage.load(),
    gallery.firstChild
  );
});

优化效果:

  1. 延迟加载大资源
  2. 提供友好的占位体验
  3. 避免不必要的网络请求

装饰器模式增强功能

在不修改原对象基础上动态添加功能:

function memoize(target, name, descriptor) {
  const originalMethod = descriptor.value;
  const cache = new Map();

  descriptor.value = function(...args) {
    const key = JSON.stringify(args);
    if (cache.has(key)) {
      console.log('Returning cached result');
      return cache.get(key);
    }
    
    const result = originalMethod.apply(this, args);
    cache.set(key, result);
    return result;
  };

  return descriptor;
}

class Calculator {
  @memoize
  factorial(n) {
    if (n === 0 || n === 1) return 1;
    return n * this.factorial(n - 1);
  }
}

// 使用示例
const calc = new Calculator();
console.log(calc.factorial(5)); // 计算并缓存
console.log(calc.factorial(5)); // 从缓存读取

性能提升点:

  • 避免重复计算
  • 透明地添加缓存层
  • 保持原始接口不变

工厂模式优化对象创建

通过工厂方法控制实例创建过程:

class ComponentFactory {
  create(type) {
    switch (type) {
      case 'button':
        return this.createButton();
      case 'modal':
        return this.createModal();
      case 'tooltip':
        return this.createTooltip();
      default:
        throw new Error('Invalid component type');
    }
  }

  createButton() {
    const btn = document.createElement('button');
    btn.classList.add('btn', 'btn-primary');
    return btn;
  }

  createModal() {
    const modal = document.createElement('div');
    modal.classList.add('modal');
    modal.innerHTML = `
      <div class="modal-content">
        <span class="close">&times;</span>
      </div>
    `;
    return modal;
  }

  createTooltip() {
    const tooltip = document.createElement('div');
    tooltip.classList.add('tooltip');
    return tooltip;
  }
}

// 使用示例
const factory = new ComponentFactory();
const buttons = Array(10).fill(0).map(() => factory.create('button'));

优化效果:

  1. 集中管理DOM创建逻辑
  2. 复用相同配置的组件实例
  3. 统一修改点便于维护

状态模式管理交互流程

将状态转移逻辑封装在独立对象中:

class FormState {
  constructor(form) {
    this.form = form;
  }

  next() {}
  previous() {}
}

class DraftState extends FormState {
  next() {
    this.form.setState(new ReviewState(this.form));
  }

  previous() {
    console.log('Already at initial state');
  }
}

class ReviewState extends FormState {
  next() {
    this.form.setState(new SubmittedState(this.form));
  }

  previous() {
    this.form.setState(new DraftState(this.form));
  }
}

class SubmittedState extends FormState {
  next() {
    console.log('Form already submitted');
  }

  previous() {
    this.form.setState(new ReviewState(this.form));
  }
}

class MultiStepForm {
  constructor() {
    this.setState(new DraftState(this));
  }

  setState(state) {
    this.currentState = state;
    this.updateUI();
  }

  updateUI() {
    // 根据状态更新界面
    console.log(`UI updated to ${this.currentState.constructor.name}`);
  }

  next() {
    this.currentState.next();
  }

  previous() {
    this.currentState.previous();
  }
}

// 使用示例
const form = new MultiStepForm();
form.next(); // Draft -> Review
form.next(); // Review -> Submitted
form.previous(); // Submitted -> Review

性能优势:

  1. 避免大量条件判断
  2. 状态转换逻辑集中管理
  3. 减少不必要的UI更新

命令模式封装操作

将请求封装为对象,支持撤销和队列操作:

class Command {
  constructor(receiver) {
    this.receiver = receiver;
    this.executedCommands = [];
  }

  execute() {}
  undo() {}
}

class ResizeCommand extends Command {
  constructor(receiver, oldSize, newSize) {
    super(receiver);
    this.oldSize = oldSize;
    this.newSize = newSize;
  }

  execute() {
    this.receiver.resize(this.newSize);
    this.executedCommands.push(this);
  }

  undo() {
    this.receiver.resize(this.oldSize);
  }
}

class ElementReceiver {
  constructor(element) {
    this.element = element;
    this.size = 100;
  }

  resize(newSize) {
    this.size = newSize;
    this.element.style.width = `${newSize}px`;
    this.element.style.height = `${newSize}px`;
    console.log(`Resized to ${newSize}px`);
  }
}

// 使用示例
const element = document.getElementById('resizable');
const receiver = new ElementReceiver(element);
const resize100to200 = new ResizeCommand(receiver, 100, 200);
const resize200to300 = new ResizeCommand(receiver, 200, 300);

resize100to200.execute(); // 100 -> 200
resize200to300.execute(); // 200 -> 300

// 撤销操作
resize200to300.undo(); // 300 -> 200
resize100to200.undo(); // 200 -> 100

优化价值:

  1. 实现操作历史记录
  2. 支持批量执行和撤销
  3. 解耦操作发起者和执行者

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

  • 建站时间:2013/03/16
  • 本站运行
  • 文章数量
  • 总访问量
微信公众号
每次关注
都是向财富自由迈进的一步