阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > 前端性能优化中的设计模式实践

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

作者:陈川 阅读数:59834人阅读 分类: JavaScript

性能优化的设计模式基础

设计模式在前端性能优化中扮演着关键角色,它们提供了经过验证的解决方案来处理常见性能瓶颈。理解这些模式如何与性能优化相结合,是构建高效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

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌