阅读视图

发现新文章,点击刷新页面。

JavaScript性能与优化:手写实现关键优化技术

引言

在前端开发中,性能优化不仅仅是使用现成的库和工具,理解其底层原理并能够手写实现是关键。通过手写这些优化技术,我们可以:

  • 更深入地理解性能瓶颈
  • 根据具体场景定制优化方案
  • 避免引入不必要的依赖
  • 提升解决问题的能力

本文将深入探讨JavaScript性能优化的核心手写实现,每个技术点都将包含完整的实现代码和应用场景。

一、虚拟列表实现(Virtual List)

虚拟列表是处理大数据列表渲染的核心技术,通过只渲染可视区域内的元素来大幅提升性能。

1.1 核心原理
class VirtualList {
  constructor(options) {
    this.container = options.container;
    this.itemHeight = options.itemHeight;
    this.totalItems = options.totalItems;
    this.bufferSize = options.bufferSize || 5; // 上下缓冲区域
    this.renderItem = options.renderItem;
    
    this.visibleItems = [];
    this.startIndex = 0;
    this.endIndex = 0;
    
    this.init();
  }

  init() {
    // 创建容器
    this.viewport = document.createElement('div');
    this.viewport.style.position = 'relative';
    this.viewport.style.height = `${this.totalItems * this.itemHeight}px`;
    this.viewport.style.overflow = 'hidden';
    
    this.content = document.createElement('div');
    this.content.style.position = 'absolute';
    this.content.style.top = '0';
    this.content.style.left = '0';
    this.content.style.width = '100%';
    
    this.container.appendChild(this.viewport);
    this.viewport.appendChild(this.content);
    
    // 绑定滚动事件
    this.viewport.addEventListener('scroll', this.handleScroll.bind(this));
    
    // 初始渲染
    this.calculateVisibleRange();
    this.renderVisibleItems();
  }

  calculateVisibleRange() {
    const scrollTop = this.viewport.scrollTop;
    const visibleHeight = this.viewport.clientHeight;
    
    // 计算可视区域起始和结束索引
    this.startIndex = Math.max(
      0,
      Math.floor(scrollTop / this.itemHeight) - this.bufferSize
    );
    
    this.endIndex = Math.min(
      this.totalItems - 1,
      Math.ceil((scrollTop + visibleHeight) / this.itemHeight) + this.bufferSize
    );
  }

  renderVisibleItems() {
    // 移除不在可视区域的元素
    this.visibleItems.forEach(item => {
      if (item.index < this.startIndex || item.index > this.endIndex) {
        item.element.remove();
      }
    });
    
    // 更新可见项数组
    this.visibleItems = this.visibleItems.filter(
      item => item.index >= this.startIndex && item.index <= this.endIndex
    );
    
    // 创建新的可见项
    for (let i = this.startIndex; i <= this.endIndex; i++) {
      const existingItem = this.visibleItems.find(item => item.index === i);
      
      if (!existingItem) {
        const itemElement = document.createElement('div');
        itemElement.style.position = 'absolute';
        itemElement.style.top = `${i * this.itemHeight}px`;
        itemElement.style.height = `${this.itemHeight}px`;
        itemElement.style.width = '100%';
        
        this.renderItem(itemElement, i);
        
        this.content.appendChild(itemElement);
        this.visibleItems.push({ index: i, element: itemElement });
      }
    }
    
    // 更新内容区域位置
    this.content.style.transform = `translateY(${this.startIndex * this.itemHeight}px)`;
  }

  handleScroll() {
    requestAnimationFrame(() => {
      this.calculateVisibleRange();
      this.renderVisibleItems();
    });
  }

  updateItem(index, data) {
    const item = this.visibleItems.find(item => item.index === index);
    if (item) {
      this.renderItem(item.element, index, data);
    }
  }

  destroy() {
    this.viewport.removeEventListener('scroll', this.handleScroll);
    this.container.removeChild(this.viewport);
  }
}

// 使用示例
const listContainer = document.getElementById('list-container');

const virtualList = new VirtualList({
  container: listContainer,
  itemHeight: 50,
  totalItems: 10000,
  bufferSize: 10,
  renderItem: (element, index) => {
    element.textContent = `Item ${index + 1}`;
    element.style.borderBottom = '1px solid #eee';
    element.style.padding = '10px';
  }
});

// 动态更新
setTimeout(() => {
  virtualList.updateItem(5, 'Updated Item 6');
}, 2000);
1.2 带动态高度的虚拟列表
class DynamicVirtualList {
  constructor(options) {
    this.container = options.container;
    this.totalItems = options.totalItems;
    this.renderItem = options.renderItem;
    this.estimateHeight = options.estimateHeight || 50;
    this.bufferSize = options.bufferSize || 5;
    
    this.itemHeights = new Array(this.totalItems).fill(null);
    this.itemPositions = new Array(this.totalItems).fill(0);
    this.visibleItems = [];
    this.cachedItems = new Map();
    
    this.init();
  }

  init() {
    this.viewport = document.createElement('div');
    this.viewport.style.position = 'relative';
    this.viewport.style.height = '500px';
    this.viewport.style.overflow = 'auto';
    
    this.content = document.createElement('div');
    this.content.style.position = 'relative';
    
    this.viewport.appendChild(this.content);
    this.container.appendChild(this.viewport);
    
    // 计算预估的总高度
    this.calculatePositions();
    this.updateContentHeight();
    
    this.viewport.addEventListener('scroll', this.handleScroll.bind(this));
    
    // 初始渲染
    this.calculateVisibleRange();
    this.renderVisibleItems();
  }

  calculatePositions() {
    let totalHeight = 0;
    for (let i = 0; i < this.totalItems; i++) {
      this.itemPositions[i] = totalHeight;
      totalHeight += this.itemHeights[i] || this.estimateHeight;
    }
    this.totalHeight = totalHeight;
  }

  updateContentHeight() {
    this.content.style.height = `${this.totalHeight}px`;
  }

  calculateVisibleRange() {
    const scrollTop = this.viewport.scrollTop;
    const viewportHeight = this.viewport.clientHeight;
    
    // 二分查找起始索引
    let start = 0;
    let end = this.totalItems - 1;
    
    while (start <= end) {
      const mid = Math.floor((start + end) / 2);
      if (this.itemPositions[mid] <= scrollTop) {
        start = mid + 1;
      } else {
        end = mid - 1;
      }
    }
    
    this.startIndex = Math.max(0, end - this.bufferSize);
    
    // 查找结束索引
    let currentHeight = scrollTop;
    this.endIndex = this.startIndex;
    
    while (
      this.endIndex < this.totalItems &&
      currentHeight < scrollTop + viewportHeight
    ) {
      currentHeight += this.itemHeights[this.endIndex] || this.estimateHeight;
      this.endIndex++;
    }
    
    this.endIndex = Math.min(
      this.totalItems - 1,
      this.endIndex + this.bufferSize
    );
  }

  renderVisibleItems() {
    // 更新可见项
    const newVisibleItems = [];
    
    for (let i = this.startIndex; i <= this.endIndex; i++) {
      let itemElement = this.cachedItems.get(i);
      
      if (!itemElement) {
        itemElement = document.createElement('div');
        itemElement.style.position = 'absolute';
        itemElement.style.top = `${this.itemPositions[i]}px`;
        itemElement.style.width = '100%';
        
        this.renderItem(itemElement, i);
        this.cachedItems.set(i, itemElement);
        this.content.appendChild(itemElement);
        
        // 测量实际高度
        if (this.itemHeights[i] === null) {
          this.itemHeights[i] = itemElement.offsetHeight;
          this.calculatePositions();
          this.updateContentHeight();
          
          // 重新计算位置
          itemElement.style.top = `${this.itemPositions[i]}px`;
        }
      }
      
      newVisibleItems.push({ index: i, element: itemElement });
    }
    
    // 隐藏不在可视区域的元素
    this.visibleItems.forEach(({ index, element }) => {
      if (index < this.startIndex || index > this.endIndex) {
        element.style.display = 'none';
      }
    });
    
    // 显示可见元素
    newVisibleItems.forEach(({ index, element }) => {
      element.style.display = '';
      element.style.top = `${this.itemPositions[index]}px`;
    });
    
    this.visibleItems = newVisibleItems;
  }

  handleScroll() {
    requestAnimationFrame(() => {
      this.calculateVisibleRange();
      this.renderVisibleItems();
    });
  }

  updateItem(index, data) {
    const itemElement = this.cachedItems.get(index);
    if (itemElement) {
      const oldHeight = this.itemHeights[index] || this.estimateHeight;
      
      this.renderItem(itemElement, index, data);
      
      const newHeight = itemElement.offsetHeight;
      if (oldHeight !== newHeight) {
        this.itemHeights[index] = newHeight;
        this.calculatePositions();
        this.updateContentHeight();
        this.renderVisibleItems();
      }
    }
  }
}

二、图片懒加载(Lazy Loading)

2.1 基于IntersectionObserver的实现
class LazyImageLoader {
  constructor(options = {}) {
    this.options = {
      root: null,
      rootMargin: '0px',
      threshold: 0.1,
      placeholder: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
      errorImage: null,
      loadingClass: 'lazy-loading',
      loadedClass: 'lazy-loaded',
      errorClass: 'lazy-error',
      ...options
    };
    
    this.images = new Map();
    this.observer = null;
    this.fallbackTimeout = 3000; // 降级超时时间
    
    this.init();
  }

  init() {
    if ('IntersectionObserver' in window) {
      this.observer = new IntersectionObserver(
        this.handleIntersection.bind(this),
        this.options
      );
    } else {
      this.useFallback();
    }
    
    // 预连接DNS和预加载
    this.addPreconnect();
  }

  addPreconnect() {
    const domains = new Set();
    
    // 收集所有图片的域名
    document.querySelectorAll('img[data-src]').forEach(img => {
      const src = img.getAttribute('data-src');
      if (src) {
        try {
          const url = new URL(src, window.location.origin);
          domains.add(url.origin);
        } catch (e) {
          console.warn('Invalid URL:', src);
        }
      }
    });
    
    // 添加preconnect链接
    domains.forEach(domain => {
      const link = document.createElement('link');
      link.rel = 'preconnect';
      link.href = domain;
      link.crossOrigin = 'anonymous';
      document.head.appendChild(link);
    });
  }

  registerImage(imgElement) {
    if (!(imgElement instanceof HTMLImageElement)) {
      throw new Error('Element must be an image');
    }

    const src = imgElement.getAttribute('data-src');
    if (!src) return;

    // 保存原始属性
    imgElement.setAttribute('data-lazy-src', src);
    
    // 设置占位符
    if (imgElement.src !== this.options.placeholder) {
      imgElement.setAttribute('data-original-src', imgElement.src);
      imgElement.src = this.options.placeholder;
    }
    
    imgElement.classList.add(this.options.loadingClass);
    
    // 添加到观察列表
    this.images.set(imgElement, {
      src,
      loaded: false,
      loadAttempted: false,
      observerAttached: false
    });
    
    this.attachObserver(imgElement);
  }

  attachObserver(imgElement) {
    if (this.observer && !this.images.get(imgElement)?.observerAttached) {
      this.observer.observe(imgElement);
      this.images.get(imgElement).observerAttached = true;
    }
  }

  handleIntersection(entries) {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        this.loadImage(img);
        this.observer?.unobserve(img);
      }
    });
  }

  async loadImage(imgElement) {
    const imageData = this.images.get(imgElement);
    if (!imageData || imageData.loadAttempted) return;

    imageData.loadAttempted = true;
    
    // 移除加载类,添加加载中类
    imgElement.classList.remove(this.options.loadingClass);
    imgElement.classList.add(this.options.loadingClass);
    
    // 创建加载超时
    const loadTimeout = setTimeout(() => {
      if (!imageData.loaded) {
        this.handleImageError(imgElement, new Error('Image load timeout'));
      }
    }, this.fallbackTimeout);
    
    try {
      // 预加载图片
      await this.preloadImage(imageData.src);
      
      // 应用图片
      this.applyImage(imgElement, imageData.src);
      
      clearTimeout(loadTimeout);
      
      // 更新状态
      imageData.loaded = true;
      imgElement.classList.remove(this.options.loadingClass);
      imgElement.classList.add(this.options.loadedClass);
      
      // 触发事件
      this.dispatchEvent(imgElement, 'lazyload', { src: imageData.src });
      
      // 预加载相邻图片
      this.preloadAdjacentImages(imgElement);
      
    } catch (error) {
      this.handleImageError(imgElement, error);
    }
  }

  async preloadImage(src) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      
      img.onload = () => {
        img.onload = img.onerror = null;
        resolve(img);
      };
      
      img.onerror = (err) => {
        img.onload = img.onerror = null;
        reject(new Error(`Failed to load image: ${src}`));
      };
      
      // 设置crossOrigin属性
      if (src.startsWith('http')) {
        img.crossOrigin = 'anonymous';
      }
      
      img.src = src;
    });
  }

  applyImage(imgElement, src) {
    // 使用requestAnimationFrame确保流畅
    requestAnimationFrame(() => {
      imgElement.src = src;
      
      // 如果有srcset也更新
      const srcset = imgElement.getAttribute('data-srcset');
      if (srcset) {
        imgElement.srcset = srcset;
        imgElement.removeAttribute('data-srcset');
      }
      
      // 移除data-src属性
      imgElement.removeAttribute('data-src');
      imgElement.removeAttribute('data-lazy-src');
    });
  }

  preloadAdjacentImages(currentImg) {
    const allImages = Array.from(this.images.keys());
    const currentIndex = allImages.indexOf(currentImg);
    
    if (currentIndex !== -1) {
      // 预加载前后各2张图片
      const indices = [
        currentIndex - 2, currentIndex - 1,
        currentIndex + 1, currentIndex + 2
      ];
      
      indices.forEach(index => {
        if (index >= 0 && index < allImages.length) {
          const img = allImages[index];
          const imgData = this.images.get(img);
          
          if (!imgData.loaded && !imgData.loadAttempted) {
            this.attachObserver(img);
          }
        }
      });
    }
  }

  handleImageError(imgElement, error) {
    const imageData = this.images.get(imgElement);
    
    imgElement.classList.remove(this.options.loadingClass);
    imgElement.classList.add(this.options.errorClass);
    
    // 设置错误图片
    if (this.options.errorImage) {
      imgElement.src = this.options.errorImage;
    }
    
    // 恢复原始图片(如果有)
    const originalSrc = imgElement.getAttribute('data-original-src');
    if (originalSrc && originalSrc !== this.options.placeholder) {
      imgElement.src = originalSrc;
    }
    
    console.error('Lazy image load error:', error);
    this.dispatchEvent(imgElement, 'lazyloaderror', { 
      src: imageData?.src, 
      error 
    });
  }

  dispatchEvent(element, eventName, detail) {
    const event = new CustomEvent(eventName, { 
      bubbles: true,
      detail 
    });
    element.dispatchEvent(event);
  }

  useFallback() {
    // 降级方案:滚动监听
    window.addEventListener('scroll', this.handleScrollFallback.bind(this));
    window.addEventListener('resize', this.handleScrollFallback.bind(this));
    window.addEventListener('orientationchange', this.handleScrollFallback.bind(this));
    
    // 初始检查
    setTimeout(() => this.handleScrollFallback(), 100);
  }

  handleScrollFallback() {
    const viewportHeight = window.innerHeight;
    const scrollTop = window.scrollY;
    
    this.images.forEach((imageData, imgElement) => {
      if (!imageData.loaded && !imageData.loadAttempted) {
        const rect = imgElement.getBoundingClientRect();
        const elementTop = rect.top + scrollTop;
        const elementBottom = rect.bottom + scrollTop;
        
        // 判断是否在可视区域内(带缓冲区)
        if (
          elementBottom >= scrollTop - 500 && 
          elementTop <= scrollTop + viewportHeight + 500
        ) {
          this.loadImage(imgElement);
        }
      }
    });
  }

  // 批量注册
  registerAll(selector = 'img[data-src]') {
    const images = document.querySelectorAll(selector);
    images.forEach(img => this.registerImage(img));
    
    // 监听动态添加的图片
    if ('MutationObserver' in window) {
      this.mutationObserver = new MutationObserver((mutations) => {
        mutations.forEach(mutation => {
          mutation.addedNodes.forEach(node => {
            if (node.nodeType === 1) { // 元素节点
              if (node.matches && node.matches(selector)) {
                this.registerImage(node);
              }
              if (node.querySelectorAll) {
                node.querySelectorAll(selector).forEach(img => {
                  this.registerImage(img);
                });
              }
            }
          });
        });
      });
      
      this.mutationObserver.observe(document.body, {
        childList: true,
        subtree: true
      });
    }
  }

  // 手动触发加载
  loadImageNow(imgElement) {
    if (this.images.has(imgElement)) {
      this.loadImage(imgElement);
    }
  }

  // 销毁
  destroy() {
    if (this.observer) {
      this.observer.disconnect();
    }
    
    if (this.mutationObserver) {
      this.mutationObserver.disconnect();
    }
    
    window.removeEventListener('scroll', this.handleScrollFallback);
    window.removeEventListener('resize', this.handleScrollFallback);
    window.removeEventListener('orientationchange', this.handleScrollFallback);
    
    this.images.clear();
  }
}

// 使用示例
const lazyLoader = new LazyImageLoader({
  threshold: 0.01,
  placeholder: '/path/to/placeholder.jpg',
  errorImage: '/path/to/error.jpg'
});

// 注册所有懒加载图片
document.addEventListener('DOMContentLoaded', () => {
  lazyLoader.registerAll();
});

// 动态添加图片
const newImage = document.createElement('img');
newImage.setAttribute('data-src', '/path/to/image.jpg');
document.body.appendChild(newImage);
lazyLoader.registerImage(newImage);
2.2 背景图片懒加载
class LazyBackgroundLoader extends LazyImageLoader {
  constructor(options = {}) {
    super(options);
    this.attributeName = options.attributeName || 'data-bg';
  }

  registerElement(element) {
    const bgSrc = element.getAttribute(this.attributeName);
    if (!bgSrc) return;

    this.images.set(element, {
      src: bgSrc,
      loaded: false,
      loadAttempted: false,
      observerAttached: false
    });

    this.attachObserver(element);
  }

  async loadImage(element) {
    const elementData = this.images.get(element);
    if (!elementData || elementData.loadAttempted) return;

    elementData.loadAttempted = true;

    try {
      await this.preloadImage(elementData.src);
      
      requestAnimationFrame(() => {
        element.style.backgroundImage = `url("${elementData.src}")`;
        element.removeAttribute(this.attributeName);
        
        elementData.loaded = true;
        element.classList.add(this.options.loadedClass);
        
        this.dispatchEvent(element, 'lazyload', { src: elementData.src });
      });
    } catch (error) {
      this.handleImageError(element, error);
    }
  }

  registerAll(selector = `[${this.attributeName}]`) {
    const elements = document.querySelectorAll(selector);
    elements.forEach(el => this.registerElement(el));
  }
}

三、函数记忆化(Memoization)

3.1 基础记忆化实现
function memoize(fn, options = {}) {
  const {
    maxSize = Infinity,
    keyResolver = (...args) => JSON.stringify(args),
    ttl = null, // 生存时间(毫秒)
    cache = new Map()
  } = options;
  
  const stats = {
    hits: 0,
    misses: 0,
    size: 0
  };
  
  // 创建LRU缓存(最近最少使用)
  const lruKeys = [];
  
  const memoized = function(...args) {
    const key = keyResolver(...args);
    
    // 检查缓存
    if (cache.has(key)) {
      const entry = cache.get(key);
      
      // 检查TTL
      if (ttl && Date.now() - entry.timestamp > ttl) {
        cache.delete(key);
        stats.size--;
        stats.misses++;
      } else {
        // 更新LRU顺序
        if (maxSize < Infinity) {
          const index = lruKeys.indexOf(key);
          if (index > -1) {
            lruKeys.splice(index, 1);
            lruKeys.unshift(key);
          }
        }
        
        stats.hits++;
        return entry.value;
      }
    }
    
    // 计算新值
    stats.misses++;
    const result = fn.apply(this, args);
    
    // 缓存结果
    const entry = {
      value: result,
      timestamp: Date.now()
    };
    
    cache.set(key, entry);
    stats.size++;
    
    // 处理LRU缓存
    if (maxSize < Infinity) {
      lruKeys.unshift(key);
      
      if (cache.size > maxSize) {
        const lruKey = lruKeys.pop();
        cache.delete(lruKey);
        stats.size--;
      }
    }
    
    return result;
  };
  
  // 添加工具方法
  memoized.clear = function() {
    cache.clear();
    lruKeys.length = 0;
    stats.hits = stats.misses = stats.size = 0;
  };
  
  memoized.delete = function(...args) {
    const key = keyResolver(...args);
    const deleted = cache.delete(key);
    if (deleted) {
      const index = lruKeys.indexOf(key);
      if (index > -1) lruKeys.splice(index, 1);
      stats.size--;
    }
    return deleted;
  };
  
  memoized.has = function(...args) {
    const key = keyResolver(...args);
    return cache.has(key);
  };
  
  memoized.getStats = function() {
    return { ...stats };
  };
  
  memoized.getCache = function() {
    return new Map(cache);
  };
  
  return memoized;
}

// 使用示例
function expensiveCalculation(n) {
  console.log('Calculating...', n);
  let result = 0;
  for (let i = 0; i < n * 1000000; i++) {
    result += Math.sqrt(i);
  }
  return result;
}

const memoizedCalculation = memoize(expensiveCalculation, {
  maxSize: 100,
  ttl: 60000 // 1分钟缓存
});

// 第一次调用会计算
console.log(memoizedCalculation(10));
// 第二次调用直接从缓存读取
console.log(memoizedCalculation(10));

// 查看统计
console.log(memoizedCalculation.getStats());
3.2 异步函数记忆化
function memoizeAsync(fn, options = {}) {
  const {
    maxSize = Infinity,
    keyResolver = (...args) => JSON.stringify(args),
    ttl = null
  } = options;
  
  const cache = new Map();
  const pendingPromises = new Map();
  const lruKeys = [];
  
  const memoized = async function(...args) {
    const key = keyResolver(...args);
    
    // 检查缓存
    if (cache.has(key)) {
      const entry = cache.get(key);
      
      if (ttl && Date.now() - entry.timestamp > ttl) {
        cache.delete(key);
        const index = lruKeys.indexOf(key);
        if (index > -1) lruKeys.splice(index, 1);
      } else {
        if (maxSize < Infinity) {
          const index = lruKeys.indexOf(key);
          if (index > -1) {
            lruKeys.splice(index, 1);
            lruKeys.unshift(key);
          }
        }
        return entry.value;
      }
    }
    
    // 检查是否已经在执行中
    if (pendingPromises.has(key)) {
      return pendingPromises.get(key);
    }
    
    // 创建新的Promise
    const promise = (async () => {
      try {
        const result = await fn.apply(this, args);
        
        // 缓存结果
        cache.set(key, {
          value: result,
          timestamp: Date.now()
        });
        
        if (maxSize < Infinity) {
          lruKeys.unshift(key);
          
          if (cache.size > maxSize) {
            const lruKey = lruKeys.pop();
            cache.delete(lruKey);
          }
        }
        
        return result;
      } finally {
        pendingPromises.delete(key);
      }
    })();
    
    pendingPromises.set(key, promise);
    return promise;
  };
  
  memoized.clear = () => {
    cache.clear();
    pendingPromises.clear();
    lruKeys.length = 0;
  };
  
  memoized.delete = (...args) => {
    const key = keyResolver(...args);
    const deleted = cache.delete(key);
    if (deleted) {
      const index = lruKeys.indexOf(key);
      if (index > -1) lruKeys.splice(index, 1);
    }
    pendingPromises.delete(key);
    return deleted;
  };
  
  memoized.has = (...args) => {
    const key = keyResolver(...args);
    return cache.has(key);
  };
  
  return memoized;
}

// 使用示例
async function fetchUserData(userId) {
  console.log('Fetching user data for:', userId);
  const response = await fetch(`/api/users/${userId}`);
  return response.json();
}

const memoizedFetchUserData = memoizeAsync(fetchUserData, {
  ttl: 30000 // 30秒缓存
});

// 多个组件同时请求同一个用户数据
Promise.all([
  memoizedFetchUserData(1),
  memoizedFetchUserData(1),
  memoizedFetchUserData(1)
]).then(results => {
  console.log('All results:', results);
  // 只会有一次实际的网络请求
});
3.3 React Hook记忆化
import { useRef, useCallback } from 'react';

function useMemoizedCallback(fn, dependencies = []) {
  const cacheRef = useRef(new Map());
  const fnRef = useRef(fn);
  
  // 更新函数引用
  fnRef.current = fn;
  
  const memoizedFn = useCallback((...args) => {
    const cache = cacheRef.current;
    const key = JSON.stringify(args);
    
    if (cache.has(key)) {
      return cache.get(key);
    }
    
    const result = fnRef.current(...args);
    cache.set(key, result);
    return result;
  }, dependencies);
  
  // 清理函数
  const clearCache = useCallback(() => {
    cacheRef.current.clear();
  }, []);
  
  return [memoizedFn, clearCache];
}

// React组件使用示例
function ExpensiveComponent({ data }) {
  const [processData, clearCache] = useMemoizedCallback(
    (item) => {
      // 昂贵的计算
      return item.value * Math.sqrt(item.weight);
    },
    [data]
  );
  
  return (
    <div>
      {data.map(item => (
        <div key={item.id}>
          {processData(item)}
        </div>
      ))}
      <button onClick={clearCache}>Clear Cache</button>
    </div>
  );
}

四、请求防重和缓存(Deduplication & Caching)

4.1 请求防重系统
class RequestDeduplicator {
  constructor(options = {}) {
    this.options = {
      defaultTtl: 60000, // 默认缓存时间1分钟
      maxCacheSize: 100,
      ...options
    };
    
    this.pendingRequests = new Map();
    this.cache = new Map();
    this.cacheTimestamps = new Map();
    this.stats = {
      duplicatesPrevented: 0,
      cacheHits: 0,
      cacheMisses: 0
    };
  }

  generateKey(config) {
    // 生成请求的唯一标识符
    const { url, method = 'GET', params = {}, data = {} } = config;
    
    const keyParts = [
      method.toUpperCase(),
      url,
      JSON.stringify(params),
      JSON.stringify(data)
    ];
    
    return keyParts.join('|');
  }

  async request(config) {
    const key = this.generateKey(config);
    const now = Date.now();
    
    // 检查缓存
    if (this.cache.has(key)) {
      const { data, timestamp } = this.cache.get(key);
      const ttl = config.ttl || this.options.defaultTtl;
      
      if (now - timestamp < ttl) {
        this.stats.cacheHits++;
        return Promise.resolve(data);
      } else {
        // 缓存过期
        this.cache.delete(key);
        this.cacheTimestamps.delete(key);
      }
    }
    
    this.stats.cacheMisses++;
    
    // 检查是否有相同的请求正在进行中
    if (this.pendingRequests.has(key)) {
      this.stats.duplicatesPrevented++;
      return this.pendingRequests.get(key);
    }
    
    // 创建新的请求
    const requestPromise = this.executeRequest(config);
    
    // 存储进行中的请求
    this.pendingRequests.set(key, requestPromise);
    
    try {
      const result = await requestPromise;
      
      // 缓存成功的结果
      if (config.cache !== false) {
        this.cache.set(key, {
          data: result,
          timestamp: now
        });
        this.cacheTimestamps.set(key, now);
        
        // 清理过期的缓存
        this.cleanupCache();
      }
      
      return result;
    } finally {
      // 移除进行中的请求
      this.pendingRequests.delete(key);
    }
  }

  async executeRequest(config) {
    const { url, method = 'GET', params = {}, data = {}, headers = {} } = config;
    
    // 构建请求URL
    let requestUrl = url;
    if (params && Object.keys(params).length > 0) {
      const queryString = new URLSearchParams(params).toString();
      requestUrl += `?${queryString}`;
    }
    
    // 发送请求
    const response = await fetch(requestUrl, {
      method,
      headers: {
        'Content-Type': 'application/json',
        ...headers
      },
      body: method !== 'GET' && method !== 'HEAD' ? JSON.stringify(data) : undefined
    });
    
    if (!response.ok) {
      throw new Error(`Request failed: ${response.status}`);
    }
    
    return response.json();
  }

  cleanupCache() {
    const now = Date.now();
    const maxAge = this.options.defaultTtl;
    
    // 清理过期缓存
    for (const [key, timestamp] of this.cacheTimestamps.entries()) {
      if (now - timestamp > maxAge) {
        this.cache.delete(key);
        this.cacheTimestamps.delete(key);
      }
    }
    
    // 清理超出大小的缓存
    if (this.cache.size > this.options.maxCacheSize) {
      const sortedEntries = Array.from(this.cacheTimestamps.entries())
        .sort(([, a], [, b]) => a - b);
      
      const entriesToRemove = sortedEntries.slice(
        0,
        this.cache.size - this.options.maxCacheSize
      );
      
      entriesToRemove.forEach(([key]) => {
        this.cache.delete(key);
        this.cacheTimestamps.delete(key);
      });
    }
  }

  // 手动清理缓存
  clearCache(urlPattern) {
    if (urlPattern) {
      for (const key of this.cache.keys()) {
        if (key.includes(urlPattern)) {
          this.cache.delete(key);
          this.cacheTimestamps.delete(key);
        }
      }
    } else {
      this.cache.clear();
      this.cacheTimestamps.clear();
    }
  }

  // 预加载数据
  prefetch(config) {
    const key = this.generateKey(config);
    
    if (!this.cache.has(key) && !this.pendingRequests.has(key)) {
      this.request(config).catch(() => {
        // 静默失败,预加载不影响主流程
      });
    }
  }

  getStats() {
    return {
      ...this.stats,
      pendingRequests: this.pendingRequests.size,
      cachedResponses: this.cache.size
    };
  }
}

// 使用示例
const deduplicator = new RequestDeduplicator({
  defaultTtl: 30000, // 30秒
  maxCacheSize: 50
});

// 多个组件同时请求相同的数据
async function fetchUserProfile(userId) {
  const config = {
    url: `/api/users/${userId}`,
    method: 'GET',
    ttl: 60000 // 此请求特定缓存时间
  };
  
  return deduplicator.request(config);
}

// 在多个地方同时调用
Promise.all([
  fetchUserProfile(1),
  fetchUserProfile(1),
  fetchUserProfile(1)
]).then(results => {
  console.log('Results:', results);
  console.log('Stats:', deduplicator.getStats());
});

// 预加载
deduplicator.prefetch({
  url: '/api/products',
  params: { page: 1, limit: 20 }
});
4.2 分层缓存系统
class LayeredCache {
  constructor(options = {}) {
    this.layers = [];
    this.options = {
      defaultTtl: 300000, // 5分钟
      ...options
    };
    
    this.stats = {
      layerHits: {},
      totalHits: 0,
      totalMisses: 0
    };
  }

  addLayer(layer) {
    if (!layer.get || !layer.set || !layer.delete || !layer.clear) {
      throw new Error('Cache layer must implement get, set, delete, and clear methods');
    }
    
    this.layers.push(layer);
    this.stats.layerHits[layer.name || `layer_${this.layers.length}`] = 0;
  }

  async get(key) {
    this.stats.totalHits++;
    
    // 从上层开始查找
    for (let i = 0; i < this.layers.length; i++) {
      const layer = this.layers[i];
      const layerName = layer.name || `layer_${i + 1}`;
      
      try {
        const value = await layer.get(key);
        
        if (value !== undefined && value !== null) {
          // 命中,更新统计
          this.stats.layerHits[layerName] = (this.stats.layerHits[layerName] || 0) + 1;
          
          // 将数据复制到上层缓存(提升)
          for (let j = 0; j < i; j++) {
            this.layers[j].set(key, value, this.options.defaultTtl).catch(() => {});
          }
          
          return value;
        }
      } catch (error) {
        console.warn(`Cache layer ${layerName} error:`, error);
        // 继续尝试下一层
      }
    }
    
    this.stats.totalMisses++;
    return null;
  }

  async set(key, value, ttl = this.options.defaultTtl) {
    // 设置所有层级的缓存
    const promises = this.layers.map(layer => 
      layer.set(key, value, ttl).catch(() => {})
    );
    
    await Promise.all(promises);
    return value;
  }

  async delete(key) {
    // 删除所有层级的缓存
    const promises = this.layers.map(layer => 
      layer.delete(key).catch(() => {})
    );
    
    await Promise.all(promises);
  }

  async clear() {
    const promises = this.layers.map(layer => 
      layer.clear().catch(() => {})
    );
    
    await Promise.all(promises);
  }

  getStats() {
    return {
      ...this.stats,
      hitRate: this.stats.totalHits > 0 
        ? (this.stats.totalHits - this.stats.totalMisses) / this.stats.totalHits 
        : 0
    };
  }
}

// 内存缓存层实现
class MemoryCacheLayer {
  constructor(name = 'memory') {
    this.name = name;
    this.cache = new Map();
    this.timestamps = new Map();
  }

  async get(key) {
    const value = this.cache.get(key);
    
    if (value === undefined) return null;
    
    const timestamp = this.timestamps.get(key);
    if (timestamp && Date.now() > timestamp) {
      // 已过期
      this.cache.delete(key);
      this.timestamps.delete(key);
      return null;
    }
    
    return value;
  }

  async set(key, value, ttl) {
    this.cache.set(key, value);
    
    if (ttl) {
      this.timestamps.set(key, Date.now() + ttl);
    }
    
    return value;
  }

  async delete(key) {
    this.cache.delete(key);
    this.timestamps.delete(key);
  }

  async clear() {
    this.cache.clear();
    this.timestamps.clear();
  }
}

// IndexedDB缓存层实现
class IndexedDBCacheLayer {
  constructor(name = 'indexeddb', dbName = 'cache_db', storeName = 'cache_store') {
    this.name = name;
    this.dbName = dbName;
    this.storeName = storeName;
    this.db = null;
    
    this.initDB();
  }

  async initDB() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, 1);
      
      request.onupgradeneeded = (event) => {
        const db = event.target.result;
        if (!db.objectStoreNames.contains(this.storeName)) {
          db.createObjectStore(this.storeName);
        }
      };
      
      request.onsuccess = (event) => {
        this.db = event.target.result;
        resolve();
      };
      
      request.onerror = (event) => {
        reject(event.target.error);
      };
    });
  }

  async get(key) {
    if (!this.db) await this.initDB();
    
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readonly');
      const store = transaction.objectStore(this.storeName);
      const request = store.get(key);
      
      request.onsuccess = () => {
        const result = request.result;
        if (result && result.expires && Date.now() > result.expires) {
          // 已过期,删除
          this.delete(key);
          resolve(null);
        } else {
          resolve(result ? result.value : null);
        }
      };
      
      request.onerror = () => reject(request.error);
    });
  }

  async set(key, value, ttl) {
    if (!this.db) await this.initDB();
    
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      
      const item = {
        value,
        expires: ttl ? Date.now() + ttl : null,
        timestamp: Date.now()
      };
      
      const request = store.put(item, key);
      
      request.onsuccess = () => resolve(value);
      request.onerror = () => reject(request.error);
    });
  }

  async delete(key) {
    if (!this.db) await this.initDB();
    
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const request = store.delete(key);
      
      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }

  async clear() {
    if (!this.db) await this.initDB();
    
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      const request = store.clear();
      
      request.onsuccess = () => resolve();
      request.onerror = () => reject(request.error);
    });
  }
}

// 使用示例
const cache = new LayeredCache({
  defaultTtl: 300000 // 5分钟
});

// 添加内存缓存层(快速)
cache.addLayer(new MemoryCacheLayer('memory'));

// 添加IndexedDB缓存层(持久化)
cache.addLayer(new IndexedDBCacheLayer('indexeddb'));

// 使用缓存
async function getCachedData(key) {
  let data = await cache.get(key);
  
  if (!data) {
    // 从网络获取数据
    data = await fetchDataFromNetwork();
    await cache.set(key, data);
  }
  
  return data;
}

五、时间切片(Time Slicing)

5.1 基于requestIdleCallback的实现
class TimeSlicer {
  constructor(options = {}) {
    this.options = {
      timeout: 1000, // 超时时间
      taskChunkSize: 100, // 每个时间片处理的任务数
      ...options
    };
    
    this.tasks = [];
    this.isProcessing = false;
    this.currentIndex = 0;
    this.deferred = null;
    this.stats = {
      tasksProcessed: 0,
      timeSlicesUsed: 0,
      totalTime: 0
    };
  }

  addTask(task) {
    if (typeof task !== 'function') {
      throw new Error('Task must be a function');
    }
    
    this.tasks.push(task);
    return this;
  }

  addTasks(tasks) {
    tasks.forEach(task => this.addTask(task));
    return this;
  }

  process() {
    if (this.isProcessing) {
      return Promise.reject(new Error('Already processing'));
    }
    
    if (this.tasks.length === 0) {
      return Promise.resolve();
    }
    
    this.isProcessing = true;
    this.currentIndex = 0;
    this.stats.tasksProcessed = 0;
    this.stats.timeSlicesUsed = 0;
    this.stats.totalTime = 0;
    
    return new Promise((resolve, reject) => {
      this.deferred = { resolve, reject };
      this.processNextChunk();
    });
  }

  processNextChunk() {
    const startTime = performance.now();
    
    // 处理一个时间片的任务
    for (let i = 0; i < this.options.taskChunkSize; i++) {
      if (this.currentIndex >= this.tasks.length) {
        this.finishProcessing();
        return;
      }
      
      try {
        const task = this.tasks[this.currentIndex];
        task();
        this.currentIndex++;
        this.stats.tasksProcessed++;
      } catch (error) {
        this.handleError(error);
        return;
      }
    }
    
    const endTime = performance.now();
    this.stats.totalTime += endTime - startTime;
    
    // 检查是否还有任务
    if (this.currentIndex < this.tasks.length) {
      this.stats.timeSlicesUsed++;
      
      // 使用requestIdleCallback安排下一个时间片
      if ('requestIdleCallback' in window) {
        requestIdleCallback(
          () => this.processNextChunk(),
          { timeout: this.options.timeout }
        );
      } else {
        // 降级方案:使用setTimeout
        setTimeout(() => this.processNextChunk(), 0);
      }
    } else {
      this.finishProcessing();
    }
  }

  finishProcessing() {
    this.isProcessing = false;
    this.deferred.resolve({
      tasksProcessed: this.stats.tasksProcessed,
      timeSlicesUsed: this.stats.timeSlicesUsed,
      totalTime: this.stats.totalTime
    });
    this.deferred = null;
  }

  handleError(error) {
    this.isProcessing = false;
    this.deferred.reject(error);
    this.deferred = null;
  }

  clear() {
    this.tasks = [];
    this.isProcessing = false;
    this.currentIndex = 0;
  }

  getStats() {
    return { ...this.stats };
  }
}

// 使用示例
function createExpensiveTask(id) {
  return () => {
    console.log(`Processing task ${id}`);
    // 模拟耗时操作
    let sum = 0;
    for (let i = 0; i < 1000000; i++) {
      sum += Math.sqrt(i);
    }
    return sum;
  };
}

// 创建时间切片处理器
const slicer = new TimeSlicer({
  taskChunkSize: 50, // 每个时间片处理50个任务
  timeout: 2000 // 2秒超时
});

// 添加大量任务
for (let i = 0; i < 1000; i++) {
  slicer.addTask(createExpensiveTask(i));
}

// 开始处理
slicer.process().then(stats => {
  console.log('Processing completed:', stats);
}).catch(error => {
  console.error('Processing failed:', error);
});

// 可以在处理过程中添加新任务
setTimeout(() => {
  slicer.addTask(() => console.log('New task added during processing'));
}, 1000);
5.2 基于Generator的时间切片
function* taskGenerator(tasks) {
  for (let i = 0; i < tasks.length; i++) {
    yield tasks[i];
  }
}

class GeneratorTimeSlicer {
  constructor(options = {}) {
    this.options = {
      timePerSlice: 16, // 每个时间片16ms(大约一帧的时间)
      ...options
    };
    
    this.taskGenerator = null;
    this.isProcessing = false;
    this.stats = {
      tasksProcessed: 0,
      slicesUsed: 0,
      totalTime: 0
    };
  }

  processTasks(tasks) {
    if (this.isProcessing) {
      return Promise.reject(new Error('Already processing'));
    }
    
    this.isProcessing = true;
    this.taskGenerator = taskGenerator(tasks);
    this.stats = { tasksProcessed: 0, slicesUsed: 0, totalTime: 0 };
    
    return new Promise((resolve, reject) => {
      this.processNextSlice(resolve, reject);
    });
  }

  processNextSlice(resolve, reject) {
    if (!this.isProcessing) return;
    
    const sliceStart = performance.now();
    let taskResult;
    
    // 处理一个时间片
    while (true) {
      const { value: task, done } = this.taskGenerator.next();
      
      if (done) {
        this.isProcessing = false;
        resolve({
          ...this.stats,
          completed: true
        });
        return;
      }
      
      try {
        taskResult = task();
        this.stats.tasksProcessed++;
      } catch (error) {
        this.isProcessing = false;
        reject(error);
        return;
      }
      
      // 检查是否超过时间片限制
      if (performance.now() - sliceStart >= this.options.timePerSlice) {
        break;
      }
    }
    
    this.stats.slicesUsed++;
    this.stats.totalTime += performance.now() - sliceStart;
    
    // 安排下一个时间片
    if ('requestAnimationFrame' in window) {
      requestAnimationFrame(() => this.processNextSlice(resolve, reject));
    } else {
      setTimeout(() => this.processNextSlice(resolve, reject), 0);
    }
  }

  stop() {
    this.isProcessing = false;
  }
}

// 使用示例:处理大型数组
function processLargeArray(array, processItem, chunkSize = 100) {
  return new Promise((resolve) => {
    let index = 0;
    const results = [];
    
    function processChunk() {
      const chunkStart = performance.now();
      
      while (index < array.length) {
        results.push(processItem(array[index]));
        index++;
        
        // 检查是否处理了足够多的项目或时间到了
        if (index % chunkSize === 0 || 
            performance.now() - chunkStart > 16) {
          break;
        }
      }
      
      if (index < array.length) {
        // 还有更多项目,安排下一个时间片
        requestAnimationFrame(processChunk);
      } else {
        // 完成
        resolve(results);
      }
    }
    
    // 开始处理
    requestAnimationFrame(processChunk);
  });
}

// 处理10万个项目
const largeArray = Array.from({ length: 100000 }, (_, i) => i);

processLargeArray(largeArray, (item) => {
  // 对每个项目进行一些处理
  return item * Math.sqrt(item);
}, 1000).then(results => {
  console.log(`Processed ${results.length} items`);
});

六、函数节流与防抖(Throttle & Debounce)

6.1 高级节流与防抖实现
class AdvancedThrottleDebounce {
  // 节流:确保函数在一定时间内只执行一次
  static throttle(func, wait, options = {}) {
    let timeout = null;
    let previous = 0;
    let result;
    let context;
    let args;
    
    const { leading = true, trailing = true } = options;
    
    const later = () => {
      previous = !leading ? 0 : Date.now();
      timeout = null;
      if (trailing && args) {
        result = func.apply(context, args);
        context = args = null;
      }
    };
    
    const throttled = function(...params) {
      const now = Date.now();
      
      if (!previous && !leading) {
        previous = now;
      }
      
      const remaining = wait - (now - previous);
      context = this;
      args = params;
      
      if (remaining <= 0 || remaining > wait) {
        if (timeout) {
          clearTimeout(timeout);
          timeout = null;
        }
        previous = now;
        result = func.apply(context, args);
        context = args = null;
      } else if (!timeout && trailing) {
        timeout = setTimeout(later, remaining);
      }
      
      return result;
    };
    
    throttled.cancel = () => {
      clearTimeout(timeout);
      previous = 0;
      timeout = context = args = null;
    };
    
    return throttled;
  }

  // 防抖:确保函数在最后一次调用后一定时间才执行
  static debounce(func, wait, options = {}) {
    let timeout = null;
    let result;
    let context;
    let args;
    let lastCallTime;
    let lastInvokeTime = 0;
    
    const { 
      leading = false, 
      trailing = true,
      maxWait 
    } = options;
    
    const invokeFunc = (time) => {
      lastInvokeTime = time;
      result = func.apply(context, args);
      context = args = null;
      return result;
    };
    
    const leadingEdge = (time) => {
      lastInvokeTime = time;
      
      if (trailing) {
        timeout = setTimeout(timerExpired, wait);
      }
      
      return leading ? invokeFunc(time) : result;
    };
    
    const remainingWait = (time) => {
      const timeSinceLastCall = time - lastCallTime;
      const timeSinceLastInvoke = time - lastInvokeTime;
      const timeWaiting = wait - timeSinceLastCall;
      
      return maxWait === undefined
        ? timeWaiting
        : Math.min(timeWaiting, maxWait - timeSinceLastInvoke);
    };
    
    const shouldInvoke = (time) => {
      const timeSinceLastCall = time - lastCallTime;
      const timeSinceLastInvoke = time - lastInvokeTime;
      
      return (
        lastCallTime === undefined || 
        timeSinceLastCall >= wait ||
        timeSinceLastCall < 0 ||
        (maxWait !== undefined && timeSinceLastInvoke >= maxWait)
      );
    };
    
    const timerExpired = () => {
      const time = Date.now();
      if (shouldInvoke(time)) {
        return trailingEdge(time);
      }
      timeout = setTimeout(timerExpired, remainingWait(time));
    };
    
    const trailingEdge = (time) => {
      timeout = null;
      
      if (trailing && args) {
        return invokeFunc(time);
      }
      
      context = args = null;
      return result;
    };
    
    const debounced = function(...params) {
      const time = Date.now();
      const isInvoking = shouldInvoke(time);
      
      context = this;
      args = params;
      lastCallTime = time;
      
      if (isInvoking) {
        if (!timeout && leading) {
          return leadingEdge(lastCallTime);
        }
        
        if (maxWait !== undefined) {
          timeout = setTimeout(timerExpired, wait);
          return invokeFunc(lastCallTime);
        }
      }
      
      if (!timeout) {
        timeout = setTimeout(timerExpired, wait);
      }
      
      return result;
    };
    
    debounced.cancel = () => {
      if (timeout !== null) {
        clearTimeout(timeout);
      }
      lastInvokeTime = 0;
      lastCallTime = 0;
      timeout = context = args = null;
    };
    
    debounced.flush = () => {
      return timeout ? trailingEdge(Date.now()) : result;
    };
    
    return debounced;
  }

  // 立即执行的防抖(第一次立即执行,然后防抖)
  static immediateDebounce(func, wait) {
    let timeout;
    let immediate = true;
    
    return function(...args) {
      const context = this;
      
      if (immediate) {
        func.apply(context, args);
        immediate = false;
      }
      
      clearTimeout(timeout);
      timeout = setTimeout(() => {
        immediate = true;
      }, wait);
    };
  }

  // 节流+防抖组合
  static throttleDebounce(func, wait, options = {}) {
    const {
      throttleWait = wait,
      debounceWait = wait,
      leading = true,
      trailing = true
    } = options;
    
    const throttled = this.throttle(func, throttleWait, { leading, trailing });
    const debounced = this.debounce(func, debounceWait, { leading, trailing });
    
    let lastCall = 0;
    
    return function(...args) {
      const now = Date.now();
      const timeSinceLastCall = now - lastCall;
      lastCall = now;
      
      // 如果距离上次调用时间很短,使用防抖
      if (timeSinceLastCall < throttleWait) {
        return debounced.apply(this, args);
      }
      
      // 否则使用节流
      return throttled.apply(this, args);
    };
  }
}

// 使用示例
// 节流示例:滚动事件
window.addEventListener('scroll', AdvancedThrottleDebounce.throttle(
  function() {
    console.log('Scroll position:', window.scrollY);
  },
  100,
  { leading: true, trailing: true }
));

// 防抖示例:搜索输入
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', AdvancedThrottleDebounce.debounce(
  function(event) {
    console.log('Searching for:', event.target.value);
    // 实际搜索逻辑
  },
  300,
  { leading: false, trailing: true }
));

// 立即执行的防抖示例:按钮点击
const submitButton = document.getElementById('submit');
submitButton.addEventListener('click', AdvancedThrottleDebounce.immediateDebounce(
  function() {
    console.log('Submit clicked');
    // 提交逻辑
  },
  1000
));

// 组合示例:调整窗口大小
window.addEventListener('resize', AdvancedThrottleDebounce.throttleDebounce(
  function() {
    console.log('Window resized');
    // 调整布局逻辑
  },
  200,
  { throttleWait: 100, debounceWait: 300 }
));
6.2 React Hook版本的节流防抖
import { useRef, useCallback, useEffect } from 'react';

// 使用Hook实现节流
function useThrottle(callback, delay, options = {}) {
  const { leading = true, trailing = true } = options;
  const lastCallTime = useRef(0);
  const timeout = useRef(null);
  const lastArgs = useRef(null);
  const lastThis = useRef(null);
  
  const throttled = useCallback(function(...args) {
    const now = Date.now();
    lastArgs.current = args;
    lastThis.current = this;
    
    if (!leading && !lastCallTime.current) {
      lastCallTime.current = now;
    }
    
    const remaining = delay - (now - lastCallTime.current);
    
    if (remaining <= 0 || remaining > delay) {
      if (timeout.current) {
        clearTimeout(timeout.current);
        timeout.current = null;
      }
      
      lastCallTime.current = now;
      callback.apply(this, args);
      lastArgs.current = lastThis.current = null;
    } else if (!timeout.current && trailing) {
      timeout.current = setTimeout(() => {
        lastCallTime.current = leading ? Date.now() : 0;
        timeout.current = null;
        
        if (trailing && lastArgs.current) {
          callback.apply(lastThis.current, lastArgs.current);
          lastArgs.current = lastThis.current = null;
        }
      }, remaining);
    }
  }, [callback, delay, leading, trailing]);
  
  // 清理函数
  useEffect(() => {
    return () => {
      if (timeout.current) {
        clearTimeout(timeout.current);
      }
    };
  }, []);
  
  return throttled;
}

// 使用Hook实现防抖
function useDebounce(callback, delay, options = {}) {
  const { leading = false, maxWait } = options;
  const lastCallTime = useRef(0);
  const lastInvokeTime = useRef(0);
  const timeout = useRef(null);
  const lastArgs = useRef(null);
  const lastThis = useRef(null);
  
  const debounced = useCallback(function(...args) {
    const now = Date.now();
    
    lastArgs.current = args;
    lastThis.current = this;
    lastCallTime.current = now;
    
    const invokeFunc = () => {
      lastInvokeTime.current = now;
      callback.apply(this, args);
      lastArgs.current = lastThis.current = null;
    };
    
    const shouldInvoke = () => {
      const timeSinceLastCall = now - lastCallTime.current;
      const timeSinceLastInvoke = now - lastInvokeTime.current;
      
      return (
        lastCallTime.current === 0 ||
        timeSinceLastCall >= delay ||
        timeSinceLastCall < 0 ||
        (maxWait !== undefined && timeSinceLastInvoke >= maxWait)
      );
    };
    
    if (shouldInvoke()) {
      if (!timeout.current && leading) {
        invokeFunc();
      }
      
      if (maxWait !== undefined) {
        timeout.current = setTimeout(() => {
          if (timeout.current) {
            clearTimeout(timeout.current);
            timeout.current = null;
          }
          invokeFunc();
        }, delay);
        return;
      }
    }
    
    if (!timeout.current) {
      timeout.current = setTimeout(() => {
        timeout.current = null;
        if (lastArgs.current) {
          invokeFunc();
        }
      }, delay);
    }
  }, [callback, delay, leading, maxWait]);
  
  // 清理函数
  useEffect(() => {
    return () => {
      if (timeout.current) {
        clearTimeout(timeout.current);
      }
    };
  }, []);
  
  return debounced;
}

// React组件使用示例
function SearchComponent() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  
  // 防抖搜索函数
  const debouncedSearch = useDebounce(async (searchQuery) => {
    if (!searchQuery.trim()) {
      setResults([]);
      return;
    }
    
    const response = await fetch(`/api/search?q=${encodeURIComponent(searchQuery)}`);
    const data = await response.json();
    setResults(data);
  }, 300);
  
  const handleInputChange = useCallback((event) => {
    const value = event.target.value;
    setQuery(value);
    debouncedSearch(value);
  }, [debouncedSearch]);
  
  return (
    <div>
      <input 
        type="text" 
        value={query}
        onChange={handleInputChange}
        placeholder="Search..."
      />
      <ul>
        {results.map(result => (
          <li key={result.id}>{result.name}</li>
        ))}
      </ul>
    </div>
  );
}

七、并发控制与请求池(Concurrency Control & Request Pool)

7.1 智能请求池实现
class RequestPool {
  constructor(options = {}) {
    this.options = {
      maxConcurrent: 6, // 最大并发数(浏览器限制通常是6)
      retryCount: 2, // 重试次数
      retryDelay: 1000, // 重试延迟
      timeout: 30000, // 超时时间
      priority: false, // 是否启用优先级
      ...options
    };
    
    this.queue = [];
    this.activeRequests = new Map();
    this.requestCount = 0;
    this.stats = {
      total: 0,
      success: 0,
      failed: 0,
      retried: 0,
      queued: 0,
      active: 0
    };
    
    this.paused = false;
  }

  addRequest(request, priority = 0) {
    const requestId = `req_${Date.now()}_${++this.requestCount}`;
    const requestConfig = {
      id: requestId,
      request,
      priority,
      retries: 0,
      addedAt: Date.now()
    };
    
    if (this.options.priority) {
      // 按优先级插入队列
      let insertIndex = this.queue.length;
      for (let i = 0; i < this.queue.length; i++) {
        if (priority > this.queue[i].priority) {
          insertIndex = i;
          break;
        }
      }
      this.queue.splice(insertIndex, 0, requestConfig);
    } else {
      this.queue.push(requestConfig);
    }
    
    this.stats.queued++;
    this.stats.total++;
    
    this.processQueue();
    return requestId;
  }

  async processQueue() {
    if (this.paused || this.queue.length === 0) return;
    
    // 检查可用并发数
    const availableSlots = this.options.maxConcurrent - this.activeRequests.size;
    if (availableSlots <= 0) return;
    
    // 获取要处理的任务
    const tasksToProcess = this.queue.splice(0, availableSlots);
    
    tasksToProcess.forEach(task => {
      this.executeRequest(task);
    });
  }

  async executeRequest(task) {
    const { id, request, priority, retries } = task;
    
    this.activeRequests.set(id, task);
    this.stats.queued--;
    this.stats.active++;
    
    try {
      const controller = new AbortController();
      const timeoutId = setTimeout(() => {
        controller.abort();
      }, this.options.timeout);
      
      // 执行请求
      const result = await request(controller.signal);
      
      clearTimeout(timeoutId);
      
      // 请求成功
      this.activeRequests.delete(id);
      this.stats.active--;
      this.stats.success++;
      
      // 触发成功事件
      this.emit('success', { id, result, retries });
      
      // 继续处理队列
      this.processQueue();
      
      return result;
    } catch (error) {
      clearTimeout(timeoutId);
      
      // 检查是否需要重试
      const shouldRetry = retries < this.options.retryCount && 
                         !this.isAbortError(error);
      
      if (shouldRetry) {
        this.stats.retried++;
        
        // 延迟后重试
        setTimeout(() => {
          task.retries++;
          this.queue.unshift(task);
          this.stats.queued++;
          this.processQueue();
        }, this.options.retryDelay);
      } else {
        // 最终失败
        this.activeRequests.delete(id);
        this.stats.active--;
        this.stats.failed++;
        
        // 触发失败事件
        this.emit('error', { id, error, retries });
        
        // 继续处理队列
        this.processQueue();
      }
    }
  }

  isAbortError(error) {
    return error.name === 'AbortError' || error.message === 'The user aborted a request.';
  }

  // 事件系统
  eventHandlers = new Map();
  
  on(event, handler) {
    if (!this.eventHandlers.has(event)) {
      this.eventHandlers.set(event, []);
    }
    this.eventHandlers.get(event).push(handler);
  }
  
  off(event, handler) {
    if (this.eventHandlers.has(event)) {
      const handlers = this.eventHandlers.get(event);
      const index = handlers.indexOf(handler);
      if (index > -1) {
        handlers.splice(index, 1);
      }
    }
  }
  
  emit(event, data) {
    if (this.eventHandlers.has(event)) {
      this.eventHandlers.get(event).forEach(handler => {
        try {
          handler(data);
        } catch (error) {
          console.error(`Error in event handler for ${event}:`, error);
        }
      });
    }
  }

  // 控制方法
  pause() {
    this.paused = true;
  }

  resume() {
    this.paused = false;
    this.processQueue();
  }

  cancelRequest(requestId) {
    // 从队列中移除
    const queueIndex = this.queue.findIndex(req => req.id === requestId);
    if (queueIndex > -1) {
      this.queue.splice(queueIndex, 1);
      this.stats.queued--;
      return true;
    }
    
    // 从活动请求中移除(无法真正取消fetch,但可以标记为取消)
    if (this.activeRequests.has(requestId)) {
      // 在实际应用中,这里应该取消fetch请求
      // 需要保存AbortController并在取消时调用abort()
      this.activeRequests.delete(requestId);
      this.stats.active--;
      return true;
    }
    
    return false;
  }

  clearQueue() {
    this.queue = [];
    this.stats.queued = 0;
  }

  getStats() {
    return {
      ...this.stats,
      queueLength: this.queue.length,
      activeRequests: this.activeRequests.size
    };
  }

  waitForAll() {
    return new Promise((resolve) => {
      const checkInterval = setInterval(() => {
        if (this.queue.length === 0 && this.activeRequests.size === 0) {
          clearInterval(checkInterval);
          resolve(this.stats);
        }
      }, 100);
    });
  }
}

// 使用示例
const requestPool = new RequestPool({
  maxConcurrent: 4,
  retryCount: 2,
  timeout: 10000,
  priority: true
});

// 添加请求事件监听
requestPool.on('success', ({ id, result }) => {
  console.log(`Request ${id} succeeded`);
});

requestPool.on('error', ({ id, error }) => {
  console.error(`Request ${id} failed:`, error);
});

// 创建请求函数
function createRequest(url, data = null) {
  return async (signal) => {
    const options = {
      method: data ? 'POST' : 'GET',
      headers: {
        'Content-Type': 'application/json'
      },
      signal
    };
    
    if (data) {
      options.body = JSON.stringify(data);
    }
    
    const response = await fetch(url, options);
    
    if (!response.ok) {
      throw new Error(`HTTP ${response.status}`);
    }
    
    return response.json();
  };
}

// 添加多个请求
const urls = [
  '/api/users/1',
  '/api/users/2',
  '/api/users/3',
  '/api/products/1',
  '/api/products/2',
  '/api/orders/1'
];

urls.forEach((url, index) => {
  const priority = index < 3 ? 10 : 1; // 前3个请求高优先级
  requestPool.addRequest(createRequest(url), priority);
});

// 等待所有请求完成
requestPool.waitForAll().then(stats => {
  console.log('All requests completed:', stats);
});

// 动态调整并发数
setTimeout(() => {
  requestPool.options.maxConcurrent = 2;
}, 5000);
7.2 带缓存的请求池
class CachedRequestPool extends RequestPool {
  constructor(options = {}) {
    super(options);
    
    this.cache = new Map();
    this.cacheOptions = {
      ttl: options.cacheTtl || 300000, // 5分钟
      maxSize: options.cacheMaxSize || 100,
      ...options.cacheOptions
    };
    
    this.cacheHits = 0;
    this.cacheMisses = 0;
  }

  addRequest(request, priority = 0, cacheKey = null) {
    // 生成缓存键
    const actualCacheKey = cacheKey || this.generateCacheKey(request);
    
    // 检查缓存
    if (this.cache.has(actualCacheKey)) {
      const cached = this.cache.get(actualCacheKey);
      
      if (Date.now() - cached.timestamp < this.cacheOptions.ttl) {
        this.cacheHits++;
        
        // 立即返回缓存结果
        return Promise.resolve(cached.data);
      } else {
        // 缓存过期
        this.cache.delete(actualCacheKey);
      }
    }
    
    this.cacheMisses++;
    
    // 创建包装的请求函数
    const wrappedRequest = async (signal) => {
      try {
        const result = await request(signal);
        
        // 缓存结果
        this.cache.set(actualCacheKey, {
          data: result,
          timestamp: Date.now()
        });
        
        // 清理过期缓存
        this.cleanupCache();
        
        return result;
      } catch (error) {
        throw error;
      }
    };
    
    // 添加到父类队列
    return new Promise((resolve, reject) => {
      const requestId = super.addRequest(wrappedRequest, priority);
      
      // 监听完成事件
      const successHandler = ({ id, result }) => {
        if (id === requestId) {
          resolve(result);
          this.off('success', successHandler);
          this.off('error', errorHandler);
        }
      };
      
      const errorHandler = ({ id, error }) => {
        if (id === requestId) {
          reject(error);
          this.off('success', successHandler);
          this.off('error', errorHandler);
        }
      };
      
      this.on('success', successHandler);
      this.on('error', errorHandler);
    });
  }

  generateCacheKey(request) {
    // 根据请求函数生成缓存键
    // 这是一个简单实现,实际应用中可能需要更复杂的逻辑
    return `cache_${Date.now()}_${Math.random().toString(36).substr(2)}`;
  }

  cleanupCache() {
    const now = Date.now();
    const maxAge = this.cacheOptions.ttl;
    
    // 清理过期缓存
    for (const [key, value] of this.cache.entries()) {
      if (now - value.timestamp > maxAge) {
        this.cache.delete(key);
      }
    }
    
    // 清理超出大小的缓存
    if (this.cache.size > this.cacheOptions.maxSize) {
      const entries = Array.from(this.cache.entries());
      entries.sort(([, a], [, b]) => a.timestamp - b.timestamp);
      
      const toRemove = entries.slice(0, this.cache.size - this.cacheOptions.maxSize);
      toRemove.forEach(([key]) => this.cache.delete(key));
    }
  }

  clearCache() {
    this.cache.clear();
    this.cacheHits = 0;
    this.cacheMisses = 0;
  }

  getCacheStats() {
    return {
      hits: this.cacheHits,
      misses: this.cacheMisses,
      hitRate: this.cacheHits + this.cacheMisses > 0 
        ? this.cacheHits / (this.cacheHits + this.cacheMisses)
        : 0,
      size: this.cache.size
    };
  }
}

八、数据分批处理(Batch Processing)

8.1 智能数据批处理器
class BatchProcessor {
  constructor(options = {}) {
    this.options = {
      batchSize: 100,
      delay: 100, // 延迟时间(毫秒)
      maxBatches: 10, // 最大批次数
      autoProcess: true, // 是否自动处理
      ...options
    };
    
    this.batch = [];
    this.batchQueue = [];
    this.isProcessing = false;
    this.timer = null;
    this.stats = {
      totalItems: 0,
      processedItems: 0,
      batchesProcessed: 0,
      processingTime: 0
    };
    
    if (this.options.autoProcess) {
      this.startAutoProcess();
    }
  }

  add(item) {
    this.batch.push(item);
    this.stats.totalItems++;
    
    if (this.batch.length >= this.options.batchSize) {
      this.enqueueBatch();
    } else if (this.options.autoProcess && !this.timer) {
      this.startTimer();
    }
    
    return this;
  }

  addMany(items) {
    items.forEach(item => this.add(item));
    return this;
  }

  enqueueBatch() {
    if (this.batch.length === 0) return;
    
    const batchToEnqueue = [...this.batch];
    this.batch = [];
    
    this.batchQueue.push(batchToEnqueue);
    
    // 检查队列长度
    if (this.batchQueue.length > this.options.maxBatches) {
      console.warn('Batch queue is full, consider increasing maxBatches or batchSize');
    }
    
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
    
    if (this.options.autoProcess && !this.isProcessing) {
      this.processQueue();
    }
  }

  startTimer() {
    if (this.timer) {
      clearTimeout(this.timer);
    }
    
    this.timer = setTimeout(() => {
      this.enqueueBatch();
      this.timer = null;
    }, this.options.delay);
  }

  async processQueue() {
    if (this.isProcessing || this.batchQueue.length === 0) return;
    
    this.isProcessing = true;
    
    while (this.batchQueue.length > 0) {
      const batch = this.batchQueue.shift();
      
      try {
        const startTime = Date.now();
        await this.processBatch(batch);
        const endTime = Date.now();
        
        this.stats.processedItems += batch.length;
        this.stats.batchesProcessed++;
        this.stats.processingTime += endTime - startTime;
        
        // 触发批次完成事件
        this.emit('batchComplete', {
          batch,
          size: batch.length,
          processingTime: endTime - startTime
        });
        
      } catch (error) {
        console.error('Batch processing error:', error);
        
        // 触发错误事件
        this.emit('error', {
          error,
          batch,
          size: batch.length
        });
      }
    }
    
    this.isProcessing = false;
    
    // 触发队列完成事件
    this.emit('queueEmpty', this.stats);
  }

  async processBatch(batch) {
    // 这是一个抽象方法,需要在子类中实现
    throw new Error('processBatch method must be implemented');
  }

  flush() {
    // 强制处理当前批次
    if (this.batch.length > 0) {
      this.enqueueBatch();
    }
    
    return this.processQueue();
  }

  waitForCompletion() {
    return new Promise((resolve) => {
      const checkComplete = () => {
        if (this.batch.length === 0 && 
            this.batchQueue.length === 0 && 
            !this.isProcessing) {
          resolve(this.stats);
        } else {
          setTimeout(checkComplete, 50);
        }
      };
      
      checkComplete();
    });
  }

  // 事件系统
  eventHandlers = new Map();
  
  on(event, handler) {
    if (!this.eventHandlers.has(event)) {
      this.eventHandlers.set(event, []);
    }
    this.eventHandlers.get(event).push(handler);
  }
  
  off(event, handler) {
    if (this.eventHandlers.has(event)) {
      const handlers = this.eventHandlers.get(event);
      const index = handlers.indexOf(handler);
      if (index > -1) {
        handlers.splice(index, 1);
      }
    }
  }
  
  emit(event, data) {
    if (this.eventHandlers.has(event)) {
      this.eventHandlers.get(event).forEach(handler => {
        try {
          handler(data);
        } catch (error) {
          console.error(`Error in event handler for ${event}:`, error);
        }
      });
    }
  }

  getStats() {
    return {
      ...this.stats,
      itemsInBatch: this.batch.length,
      batchesInQueue: this.batchQueue.length,
      isProcessing: this.isProcessing
    };
  }

  reset() {
    this.batch = [];
    this.batchQueue = [];
    this.isProcessing = false;
    
    if (this.timer) {
      clearTimeout(this.timer);
      this.timer = null;
    }
    
    this.stats = {
      totalItems: 0,
      processedItems: 0,
      batchesProcessed: 0,
      processingTime: 0
    };
  }
}

// 使用示例:API批量请求处理器
class ApiBatchProcessor extends BatchProcessor {
  constructor(apiEndpoint, options = {}) {
    super({
      batchSize: 50,
      delay: 500,
      ...options
    });
    
    this.apiEndpoint = apiEndpoint;
  }

  async processBatch(batch) {
    // 批量发送请求
    const response = await fetch(this.apiEndpoint, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ items: batch })
    });
    
    if (!response.ok) {
      throw new Error(`API request failed: ${response.status}`);
    }
    
    return response.json();
  }
}

// 使用示例
const processor = new ApiBatchProcessor('/api/batch-save', {
  batchSize: 100,
  delay: 1000
});

// 监听事件
processor.on('batchComplete', ({ batch, size, processingTime }) => {
  console.log(`Processed batch of ${size} items in ${processingTime}ms`);
});

processor.on('queueEmpty', (stats) => {
  console.log('All batches processed:', stats);
});

// 添加大量数据
for (let i = 0; i < 1000; i++) {
  processor.add({ id: i, data: `Item ${i}` });
}

// 等待处理完成
processor.waitForCompletion().then(stats => {
  console.log('Processing completed:', stats);
});
8.2 数据库批量操作
class DatabaseBatchProcessor extends BatchProcessor {
  constructor(dbName, storeName, options = {}) {
    super({
      batchSize: 100,
      delay: 100,
      ...options
    });
    
    this.dbName = dbName;
    this.storeName = storeName;
    this.db = null;
    
    this.initDatabase();
  }

  async initDatabase() {
    return new Promise((resolve, reject) => {
      const request = indexedDB.open(this.dbName, 1);
      
      request.onupgradeneeded = (event) => {
        const db = event.target.result;
        if (!db.objectStoreNames.contains(this.storeName)) {
          db.createObjectStore(this.storeName, { keyPath: 'id' });
        }
      };
      
      request.onsuccess = (event) => {
        this.db = event.target.result;
        resolve();
      };
      
      request.onerror = (event) => {
        reject(event.target.error);
      };
    });
  }

  async processBatch(batch) {
    if (!this.db) await this.initDatabase();
    
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readwrite');
      const store = transaction.objectStore(this.storeName);
      
      let completed = 0;
      let errors = [];
      
      batch.forEach(item => {
        const request = store.put(item);
        
        request.onsuccess = () => {
          completed++;
          if (completed === batch.length) {
            if (errors.length > 0) {
              reject(new Error(`Failed to save ${errors.length} items`));
            } else {
              resolve({ saved: batch.length });
            }
          }
        };
        
        request.onerror = (event) => {
          errors.push({ item, error: event.target.error });
          completed++;
          
          if (completed === batch.length) {
            if (errors.length > 0) {
              reject(new Error(`Failed to save ${errors.length} items`));
            } else {
              resolve({ saved: batch.length - errors.length });
            }
          }
        };
      });
    });
  }

  async queryBatch(queryFn, batchSize = 100) {
    if (!this.db) await this.initDatabase();
    
    return new Promise((resolve, reject) => {
      const transaction = this.db.transaction([this.storeName], 'readonly');
      const store = transaction.objectStore(this.storeName);
      const request = store.openCursor();
      
      const results = [];
      let processed = 0;
      
      request.onsuccess = (event) => {
        const cursor = event.target.result;
        
        if (cursor) {
          // 应用查询函数
          if (queryFn(cursor.value)) {
            results.push(cursor.value);
          }
          
          processed++;
          cursor.continue();
          
          // 批量处理
          if (processed % batchSize === 0) {
            // 短暂暂停以避免阻塞主线程
            setTimeout(() => {}, 0);
          }
        } else {
          resolve(results);
        }
      };
      
      request.onerror = (event) => {
        reject(event.target.error);
      };
    });
  }
}

// 使用示例
const dbProcessor = new DatabaseBatchProcessor('myDatabase', 'items');

// 批量添加数据
for (let i = 0; i < 10000; i++) {
  dbProcessor.add({
    id: i,
    name: `Item ${i}`,
    value: Math.random(),
    timestamp: Date.now()
  });
}

// 批量查询
dbProcessor.queryBatch(
  item => item.value > 0.5,
  500
).then(results => {
  console.log(`Found ${results.length} items with value > 0.5`);
});

九、对象池模式(Object Pool Pattern)

9.1 通用对象池实现
class ObjectPool {
  constructor(createFn, options = {}) {
    if (typeof createFn !== 'function') {
      throw new Error('createFn must be a function');
    }
    
    this.createFn = createFn;
    this.options = {
      maxSize: 100,
      minSize: 0,
      validate: null, // 验证函数
      reset: null, // 重置函数
      ...options
    };
    
    this.pool = [];
    this.active = new Set();
    this.stats = {
      created: 0,
      reused: 0,
      destroyed: 0,
      peakSize: 0
    };
    
    // 预创建对象
    this.prepopulate();
  }

  prepopulate() {
    const count = Math.min(this.options.minSize, this.options.maxSize);
    for (let i = 0; i < count; i++) {
      const obj = this.createNew();
      this.pool.push(obj);
    }
  }

  createNew() {
    const obj = this.createFn();
    this.stats.created++;
    return obj;
  }

  acquire() {
    let obj;
    
    if (this.pool.length > 0) {
      // 从池中获取
      obj = this.pool.pop();
      
      // 验证对象
      if (this.options.validate && !this.options.validate(obj)) {
        // 对象无效,销毁并创建新的
        this.destroyObject(obj);
        obj = this.createNew();
      } else {
        this.stats.reused++;
      }
    } else {
      // 池为空,创建新对象
      obj = this.createNew();
    }
    
    // 重置对象状态
    if (this.options.reset) {
      this.options.reset(obj);
    }
    
    this.active.add(obj);
    this.updatePeakSize();
    
    return obj;
  }

  release(obj) {
    if (!this.active.has(obj)) {
      console.warn('Object not active in pool');
      return;
    }
    
    this.active.delete(obj);
    
    // 检查池是否已满
    if (this.pool.length < this.options.maxSize) {
      // 重置对象
      if (this.options.reset) {
        this.options.reset(obj);
      }
      
      this.pool.push(obj);
    } else {
      // 池已满,销毁对象
      this.destroyObject(obj);
    }
  }

  destroyObject(obj) {
    // 调用清理函数(如果存在)
    if (obj.destroy && typeof obj.destroy === 'function') {
      obj.destroy();
    }
    
    this.stats.destroyed++;
  }

  updatePeakSize() {
    const totalSize = this.pool.length + this.active.size;
    if (totalSize > this.stats.peakSize) {
      this.stats.peakSize = totalSize;
    }
  }

  clear() {
    // 销毁所有对象
    [...this.pool, ...this.active].forEach(obj => {
      this.destroyObject(obj);
    });
    
    this.pool = [];
    this.active.clear();
  }

  getStats() {
    return {
      ...this.stats,
      poolSize: this.pool.length,
      activeSize: this.active.size,
      totalSize: this.pool.length + this.active.size
    };
  }

  // 执行函数并自动管理对象
  async execute(callback) {
    const obj = this.acquire();
    
    try {
      const result = await callback(obj);
      return result;
    } finally {
      this.release(obj);
    }
  }
}

// 使用示例:DOM元素池
class DOMElementPool extends ObjectPool {
  constructor(elementType, options = {}) {
    super(() => {
      const element = document.createElement(elementType);
      element.style.display = 'none'; // 初始隐藏
      document.body.appendChild(element);
      return element;
    }, options);
    
    this.elementType = elementType;
  }

  acquire(styles = {}) {
    const element = super.acquire();
    
    // 应用样式
    Object.assign(element.style, {
      display: '',
      ...styles
    });
    
    return element;
  }

  release(element) {
    // 隐藏元素
    element.style.display = 'none';
    
    // 清除内容
    element.innerHTML = '';
    
    super.release(element);
  }
}

// 使用示例
const divPool = new DOMElementPool('div', {
  maxSize: 50,
  minSize: 10,
  reset: (div) => {
    div.className = '';
    div.style.cssText = '';
    div.textContent = '';
  }
});

// 使用对象池创建临时元素
for (let i = 0; i < 1000; i++) {
  const div = divPool.acquire({
    position: 'absolute',
    left: `${Math.random() * 100}%`,
    top: `${Math.random() * 100}%`,
    width: '50px',
    height: '50px',
    backgroundColor: `hsl(${Math.random() * 360}, 100%, 50%)`
  });
  
  div.textContent = i;
  
  // 模拟使用
  setTimeout(() => {
    divPool.release(div);
  }, Math.random() * 3000);
}

// 查看统计
setTimeout(() => {
  console.log('Pool stats:', divPool.getStats());
}, 5000);
9.2 连接池实现
class ConnectionPool {
  constructor(createConnection, options = {}) {
    this.createConnection = createConnection;
    this.options = {
      maxConnections: 10,
      minConnections: 2,
      idleTimeout: 30000, // 空闲超时时间
      acquireTimeout: 5000, // 获取连接超时时间
      testOnBorrow: true, // 获取时测试连接
      ...options
    };
    
    this.pool = [];
    this.active = new Set();
    this.waiting = [];
    this.timers = new Map();
    
    this.stats = {
      created: 0,
      destroyed: 0,
      acquired: 0,
      released: 0,
      timeoutErrors: 0,
      connectionErrors: 0
    };
    
    // 初始化连接池
    this.init();
  }

  async init() {
    for (let i = 0; i < this.options.minConnections; i++) {
      await this.createAndAddConnection();
    }
  }

  async createAndAddConnection() {
    try {
      const connection = await this.createConnection();
      this.pool.push({
        connection,
        lastUsed: Date.now(),
        valid: true
      });
      
      this.stats.created++;
      return connection;
    } catch (error) {
      this.stats.connectionErrors++;
      throw error;
    }
  }

  async acquire() {
    this.stats.acquired++;
    
    // 1. 检查空闲连接
    for (let i = 0; i < this.pool.length; i++) {
      const item = this.pool[i];
      
      if (item.valid) {
        // 检查连接是否有效
        if (this.options.testOnBorrow) {
          try {
            await this.testConnection(item.connection);
          } catch (error) {
            item.valid = false;
            continue;
          }
        }
        
        // 从池中移除
        const [acquiredItem] = this.pool.splice(i, 1);
        this.active.add(acquiredItem.connection);
        
        // 设置最后使用时间
        acquiredItem.lastUsed = Date.now();
        
        return acquiredItem.connection;
      }
    }
    
    // 2. 检查是否可以创建新连接
    const totalConnections = this.pool.length + this.active.size;
    if (totalConnections < this.options.maxConnections) {
      const connection = await this.createAndAddConnection();
      this.active.add(connection);
      return connection;
    }
    
    // 3. 等待可用连接
    return new Promise((resolve, reject) => {
      const waitStart = Date.now();
      
      const waitingRequest = {
        resolve,
        reject,
        timer: setTimeout(() => {
          // 超时处理
          const index = this.waiting.indexOf(waitingRequest);
          if (index > -1) {
            this.waiting.splice(index, 1);
          }
          
          this.stats.timeoutErrors++;
          reject(new Error('Connection acquisition timeout'));
        }, this.options.acquireTimeout)
      };
      
      this.waiting.push(waitingRequest);
      
      // 立即尝试处理等待队列
      this.processWaitingQueue();
    });
  }

  release(connection) {
    if (!this.active.has(connection)) {
      console.warn('Connection not active in pool');
      return;
    }
    
    this.active.delete(connection);
    this.stats.released++;
    
    // 检查连接是否仍然有效
    if (this.isConnectionValid(connection)) {
      this.pool.push({
        connection,
        lastUsed: Date.now(),
        valid: true
      });
      
      // 清理空闲超时的连接
      this.cleanupIdleConnections();
      
      // 处理等待队列
      this.processWaitingQueue();
    } else {
      // 连接无效,销毁
      this.destroyConnection(connection);
    }
  }

  async testConnection(connection) {
    // 默认实现,子类应该覆盖这个方法
    return Promise.resolve();
  }

  isConnectionValid(connection) {
    // 默认实现,子类应该覆盖这个方法
    return true;
  }

  destroyConnection(connection) {
    // 清理连接资源
    if (connection.destroy && typeof connection.destroy === 'function') {
      connection.destroy();
    } else if (connection.close && typeof connection.close === 'function') {
      connection.close();
    }
    
    this.stats.destroyed++;
  }

  cleanupIdleConnections() {
    const now = Date.now();
    const idleTimeout = this.options.idleTimeout;
    
    for (let i = this.pool.length - 1; i >= 0; i--) {
      const item = this.pool[i];
      
      // 检查空闲时间
      if (now - item.lastUsed > idleTimeout) {
        // 保留最小连接数
        if (this.pool.length > this.options.minConnections) {
          const [idleItem] = this.pool.splice(i, 1);
          this.destroyConnection(idleItem.connection);
        }
      }
    }
  }

  processWaitingQueue() {
    while (this.waiting.length > 0 && this.pool.length > 0) {
      const waitingRequest = this.waiting.shift();
      clearTimeout(waitingRequest.timer);
      
      // 获取连接
      const item = this.pool.pop();
      this.active.add(item.connection);
      item.lastUsed = Date.now();
      
      waitingRequest.resolve(item.connection);
    }
  }

  async execute(callback) {
    const connection = await this.acquire();
    
    try {
      const result = await callback(connection);
      return result;
    } finally {
      this.release(connection);
    }
  }

  getStats() {
    return {
      ...this.stats,
      poolSize: this.pool.length,
      activeSize: this.active.size,
      waitingSize: this.waiting.length,
      totalSize: this.pool.length + this.active.size
    };
  }

  clear() {
    // 清理所有连接
    [...this.pool, ...this.active].forEach(item => {
      this.destroyConnection(item.connection || item);
    });
    
    // 清理等待队列
    this.waiting.forEach(request => {
      clearTimeout(request.timer);
      request.reject(new Error('Pool cleared'));
    });
    
    this.pool = [];
    this.active.clear();
    this.waiting = [];
  }
}

// 使用示例:WebSocket连接池
class WebSocketPool extends ConnectionPool {
  constructor(url, options = {}) {
    super(async () => {
      return new Promise((resolve, reject) => {
        const ws = new WebSocket(url);
        
        ws.onopen = () => resolve(ws);
        ws.onerror = (error) => reject(error);
      });
    }, options);
    
    this.url = url;
  }

  async testConnection(ws) {
    return new Promise((resolve, reject) => {
      if (ws.readyState === WebSocket.OPEN) {
        resolve();
      } else if (ws.readyState === WebSocket.CONNECTING) {
        // 等待连接
        const onOpen = () => {
          ws.removeEventListener('open', onOpen);
          resolve();
        };
        
        const onError = () => {
          ws.removeEventListener('error', onError);
          reject(new Error('WebSocket connection failed'));
        };
        
        ws.addEventListener('open', onOpen);
        ws.addEventListener('error', onError);
        
        // 超时
        setTimeout(() => {
          ws.removeEventListener('open', onOpen);
          ws.removeEventListener('error', onError);
          reject(new Error('WebSocket connection timeout'));
        }, 5000);
      } else {
        reject(new Error('WebSocket is not open'));
      }
    });
  }

  isConnectionValid(ws) {
    return ws.readyState === WebSocket.OPEN;
  }

  destroyConnection(ws) {
    if (ws.readyState === WebSocket.OPEN || ws.readyState === WebSocket.CONNECTING) {
      ws.close();
    }
    super.destroyConnection(ws);
  }
}

// 使用示例
const wsPool = new WebSocketPool('wss://echo.websocket.org', {
  maxConnections: 5,
  minConnections: 1,
  idleTimeout: 60000
});

// 使用连接池发送消息
async function sendMessage(message) {
  return wsPool.execute(async (ws) => {
    return new Promise((resolve, reject) => {
      const messageId = Date.now();
      
      const handler = (event) => {
        try {
          const data = JSON.parse(event.data);
          if (data.id === messageId) {
            ws.removeEventListener('message', handler);
            resolve(data);
          }
        } catch (error) {
          // 忽略解析错误
        }
      };
      
      ws.addEventListener('message', handler);
      
      // 设置超时
      setTimeout(() => {
        ws.removeEventListener('message', handler);
        reject(new Error('Message timeout'));
      }, 5000);
      
      // 发送消息
      ws.send(JSON.stringify({
        id: messageId,
        message
      }));
    });
  });
}

// 并发发送消息
Promise.all([
  sendMessage('Hello 1'),
  sendMessage('Hello 2'),
  sendMessage('Hello 3'),
  sendMessage('Hello 4'),
  sendMessage('Hello 5')
]).then(responses => {
  console.log('All messages sent:', responses);
});

十、Web Worker优化计算密集型任务

10.1 智能Worker池
class WorkerPool {
  constructor(workerScript, options = {}) {
    this.workerScript = workerScript;
    this.options = {
      maxWorkers: navigator.hardwareConcurrency || 4,
      idleTimeout: 30000, // 空闲超时时间
      ...options
    };
    
    this.workers = [];
    this.idleWorkers = [];
    this.taskQueue = [];
    this.taskCallbacks = new Map();
    this.workerStates = new Map();
    
    this.stats = {
      tasksCompleted: 0,
      tasksFailed: 0,
      workersCreated: 0,
      workersDestroyed: 0
    };
    
    // 初始化Worker
    this.initWorkers();
  }

  initWorkers() {
    const initialCount = Math.min(2, this.options.maxWorkers);
    
    for (let i = 0; i < initialCount; i++) {
      this.createWorker();
    }
  }

  createWorker() {
    if (this.workers.length >= this.options.maxWorkers) {
      return null;
    }
    
    let worker;
    
    if (typeof this.workerScript === 'string') {
      worker = new Worker(this.workerScript);
    } else if (typeof this.workerScript === 'function') {
      // 从函数创建Worker
      const workerBlob = new Blob([
        `(${this.workerScript.toString()})()`
      ], { type: 'application/javascript' });
      
      worker = new Worker(URL.createObjectURL(workerBlob));
    } else {
      throw new Error('workerScript must be a URL string or a function');
    }
    
    const workerId = this.workers.length;
    worker.id = workerId;
    
    // 设置消息处理
    worker.onmessage = (event) => {
      this.handleWorkerMessage(workerId, event);
    };
    
    worker.onerror = (error) => {
      this.handleWorkerError(workerId, error);
    };
    
    worker.onmessageerror = (error) => {
      this.handleWorkerError(workerId, error);
    };
    
    this.workers.push(worker);
    this.idleWorkers.push(workerId);
    this.workerStates.set(workerId, {
      idle: true,
      currentTask: null,
      lastUsed: Date.now()
    });
    
    this.stats.workersCreated++;
    
    return workerId;
  }

  handleWorkerMessage(workerId, event) {
    const state = this.workerStates.get(workerId);
    if (!state || !state.currentTask) return;
    
    const taskId = state.currentTask;
    const callback = this.taskCallbacks.get(taskId);
    
    if (callback) {
      if (event.data.error) {
        callback.reject(new Error(event.data.error));
        this.stats.tasksFailed++;
      } else {
        callback.resolve(event.data.result);
        this.stats.tasksCompleted++;
      }
      
      this.taskCallbacks.delete(taskId);
    }
    
    // 标记Worker为空闲
    state.idle = true;
    state.currentTask = null;
    state.lastUsed = Date.now();
    this.idleWorkers.push(workerId);
    
    // 处理下一个任务
    this.processQueue();
    
    // 清理空闲超时的Worker
    this.cleanupIdleWorkers();
  }

  handleWorkerError(workerId, error) {
    console.error(`Worker ${workerId} error:`, error);
    
    const state = this.workerStates.get(workerId);
    if (state && state.currentTask) {
      const taskId = state.currentTask;
      const callback = this.taskCallbacks.get(taskId);
      
      if (callback) {
        callback.reject(error);
        this.stats.tasksFailed++;
        this.taskCallbacks.delete(taskId);
      }
    }
    
    // 销毁Worker
    this.destroyWorker(workerId);
    
    // 创建新的Worker替换
    this.createWorker();
    
    // 处理队列中的任务
    this.processQueue();
  }

  destroyWorker(workerId) {
    const workerIndex = this.workers.findIndex(w => w.id === workerId);
    if (workerIndex === -1) return;
    
    const worker = this.workers[workerIndex];
    
    // 终止Worker
    worker.terminate();
    
    // 从数组中移除
    this.workers.splice(workerIndex, 1);
    
    // 更新其他Worker的ID
    this.workers.forEach((w, index) => {
      w.id = index;
    });
    
    // 清理状态
    this.workerStates.delete(workerId);
    
    // 从空闲列表中移除
    const idleIndex = this.idleWorkers.indexOf(workerId);
    if (idleIndex > -1) {
      this.idleWorkers.splice(idleIndex, 1);
    }
    
    this.stats.workersDestroyed++;
  }

  cleanupIdleWorkers() {
    const now = Date.now();
    const idleTimeout = this.options.idleTimeout;
    
    // 保留至少一个Worker
    while (this.idleWorkers.length > 1) {
      const workerId = this.idleWorkers[0];
      const state = this.workerStates.get(workerId);
      
      if (state && now - state.lastUsed > idleTimeout) {
        this.destroyWorker(workerId);
      } else {
        break;
      }
    }
  }

  processQueue() {
    while (this.taskQueue.length > 0 && this.idleWorkers.length > 0) {
      const task = this.taskQueue.shift();
      const workerId = this.idleWorkers.shift();
      
      this.executeTask(workerId, task);
    }
    
    // 如果没有空闲Worker但有任务,考虑创建新Worker
    if (this.taskQueue.length > 0 && this.workers.length < this.options.maxWorkers) {
      this.createWorker();
      this.processQueue();
    }
  }

  executeTask(workerId, task) {
    const worker = this.workers.find(w => w.id === workerId);
    if (!worker) return;
    
    const state = this.workerStates.get(workerId);
    if (!state) return;
    
    state.idle = false;
    state.currentTask = task.id;
    state.lastUsed = Date.now();
    
    worker.postMessage({
      taskId: task.id,
      data: task.data,
      type: task.type
    });
  }

  runTask(data, type = 'default') {
    const taskId = `task_${Date.now()}_${Math.random().toString(36).substr(2)}`;
    
    return new Promise((resolve, reject) => {
      const task = {
        id: taskId,
        data,
        type
      };
      
      this.taskCallbacks.set(taskId, { resolve, reject });
      this.taskQueue.push(task);
      
      this.processQueue();
    });
  }

  // 批量执行任务
  runTasks(tasks, type = 'default') {
    return Promise.all(
      tasks.map(taskData => this.runTask(taskData, type))
    );
  }

  // 执行函数并自动清理
  async execute(data, processor) {
    if (typeof processor !== 'function') {
      throw new Error('Processor must be a function');
    }
    
    // 将处理器函数发送到Worker
    const taskId = await this.runTask({
      data,
      processor: processor.toString()
    }, 'function');
    
    return taskId;
  }

  getStats() {
    return {
      ...this.stats,
      workers: this.workers.length,
      idleWorkers: this.idleWorkers.length,
      activeWorkers: this.workers.length - this.idleWorkers.length,
      queuedTasks: this.taskQueue.length,
      activeTasks: this.taskCallbacks.size
    };
  }

  terminate() {
    // 终止所有Worker
    this.workers.forEach(worker => {
      worker.terminate();
    });
    
    // 清理所有任务
    this.taskCallbacks.forEach(({ reject }) => {
      reject(new Error('Worker pool terminated'));
    });
    
    this.workers = [];
    this.idleWorkers = [];
    this.taskQueue = [];
    this.taskCallbacks.clear();
    this.workerStates.clear();
  }
}

// Worker脚本示例
const workerScript = function() {
  // Worker内部代码
  self.onmessage = function(event) {
    const { taskId, data, type } = event.data;
    
    try {
      let result;
      
      switch (type) {
        case 'function':
          // 执行传入的函数
          const { data: taskData, processor } = data;
          const func = eval(`(${processor})`);
          result = func(taskData);
          break;
          
        case 'calculate':
          // 计算密集型任务
          result = expensiveCalculation(data);
          break;
          
        case 'process':
          // 数据处理任务
          result = processData(data);
          break;
          
        default:
          result = data;
      }
      
      self.postMessage({ taskId, result });
    } catch (error) {
      self.postMessage({ 
        taskId, 
        error: error.message || 'Unknown error' 
      });
    }
  };
  
  function expensiveCalculation(data) {
    let result = 0;
    for (let i = 0; i < data.iterations || 1000000; i++) {
      result += Math.sqrt(i) * Math.sin(i);
    }
    return result;
  }
  
  function processData(data) {
    // 数据处理逻辑
    return data.map(item => ({
      ...item,
      processed: true,
      timestamp: Date.now()
    }));
  }
};

// 使用示例
const workerPool = new WorkerPool(workerScript, {
  maxWorkers: 4,
  idleTimeout: 60000
});

// 执行计算密集型任务
async function runCalculations() {
  const tasks = Array.from({ length: 10 }, (_, i) => ({
    iterations: 1000000 * (i + 1)
  }));
  
  const startTime = Date.now();
  
  const results = await workerPool.runTasks(tasks, 'calculate');
  
  const endTime = Date.now();
  console.log(`Calculations completed in ${endTime - startTime}ms`);
  console.log('Results:', results);
  
  return results;
}

// 执行函数
async function runCustomFunction() {
  const processor = (data) => {
    // 这是在Worker中执行的函数
    let sum = 0;
    for (let i = 0; i < data.length; i++) {
      sum += data[i] * Math.sqrt(data[i]);
    }
    return sum;
  };
  
  const data = Array.from({ length: 1000000 }, () => Math.random());
  
  const result = await workerPool.execute(data, processor);
  console.log('Custom function result:', result);
}

// 监控统计
setInterval(() => {
  console.log('Worker pool stats:', workerPool.getStats());
}, 5000);
10.2 专用Worker优化
class ImageProcessingWorker {
  constructor() {
    this.worker = this.createWorker();
    this.taskQueue = new Map();
    this.nextTaskId = 1;
  }

  createWorker() {
    const workerCode = `
      self.onmessage = function(event) {
        const { taskId, operation, imageData, params } = event.data;
        
        try {
          let result;
          
          switch (operation) {
            case 'resize':
              result = resizeImage(imageData, params);
              break;
              
            case 'filter':
              result = applyFilter(imageData, params);
              break;
              
            case 'compress':
              result = compressImage(imageData, params);
              break;
              
            default:
              throw new Error('Unknown operation: ' + operation);
          }
          
          self.postMessage({ taskId, result }, [result]);
        } catch (error) {
          self.postMessage({ taskId, error: error.message });
        }
      };
      
      function resizeImage(imageData, { width, height, quality = 0.9 }) {
        // 创建离屏Canvas
        const canvas = new OffscreenCanvas(width, height);
        const ctx = canvas.getContext('2d');
        
        // 绘制并缩放图像
        ctx.drawImage(imageData, 0, 0, width, height);
        
        // 转换为Blob
        return canvas.convertToBlob({ quality });
      }
      
      function applyFilter(imageData, { filter, intensity = 1 }) {
        const canvas = new OffscreenCanvas(
          imageData.width, 
          imageData.height
        );
        const ctx = canvas.getContext('2d');
        
        ctx.drawImage(imageData, 0, 0);
        
        const imageDataObj = ctx.getImageData(
          0, 0, 
          canvas.width, 
          canvas.height
        );
        
        // 应用滤镜
        const data = imageDataObj.data;
        for (let i = 0; i < data.length; i += 4) {
          // 简单灰度滤镜示例
          if (filter === 'grayscale') {
            const avg = (data[i] + data[i + 1] + data[i + 2]) / 3;
            data[i] = data[i + 1] = data[i + 2] = avg;
          }
          // 更多滤镜...
        }
        
        ctx.putImageData(imageDataObj, 0, 0);
        
        return canvas.convertToBlob();
      }
      
      function compressImage(imageData, { quality = 0.7 }) {
        const canvas = new OffscreenCanvas(
          imageData.width, 
          imageData.height
        );
        const ctx = canvas.getContext('2d');
        
        ctx.drawImage(imageData, 0, 0);
        
        return canvas.convertToBlob({ quality });
      }
    `;
    
    const blob = new Blob([workerCode], { type: 'application/javascript' });
    return new Worker(URL.createObjectURL(blob));
  }

  processImage(imageElement, operation, params = {}) {
    return new Promise((resolve, reject) => {
      const taskId = this.nextTaskId++;
      
      // 创建Canvas来获取ImageData
      const canvas = document.createElement('canvas');
      canvas.width = imageElement.width;
      canvas.height = imageElement.height;
      
      const ctx = canvas.getContext('2d');
      ctx.drawImage(imageElement, 0, 0);
      
      // 获取ImageData
      const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
      
      // 创建ImageBitmap(更高效)
      createImageBitmap(imageElement).then(imageBitmap => {
        // 存储回调
        this.taskQueue.set(taskId, { resolve, reject });
        
        // 发送任务到Worker
        this.worker.postMessage({
          taskId,
          operation,
          imageData: imageBitmap,
          params
        }, [imageBitmap]);
      });
    });
  }

  destroy() {
    this.worker.terminate();
    this.taskQueue.clear();
  }
}

// 使用示例
const imageProcessor = new ImageProcessingWorker();

async function processUserImage(imageFile) {
  const img = new Image();
  img.src = URL.createObjectURL(imageFile);
  
  await new Promise(resolve => {
    img.onload = resolve;
  });
  
  // 调整大小
  const resized = await imageProcessor.processImage(img, 'resize', {
    width: 800,
    height: 600,
    quality: 0.8
  });
  
  // 应用滤镜
  const filtered = await imageProcessor.processImage(img, 'filter', {
    filter: 'grayscale',
    intensity: 1
  });
  
  // 压缩
  const compressed = await imageProcessor.processImage(img, 'compress', {
    quality: 0.6
  });
  
  return {
    resized,
    filtered,
    compressed
  };
}

十一、最佳实践与性能原则

11.1 性能优化黄金法则
  1. 测量第一,优化第二
  • 使用Performance API测量关键指标
  • 优先优化瓶颈,而非微观优化
  • 建立性能基准线
  1. 延迟加载一切可能的内容
  • 图片、视频、第三方脚本
  • 非关键CSS和JavaScript
  • 路由级代码分割
  1. 缓存一切可能的内容
  • HTTP缓存策略
  • 内存缓存频繁使用的数据
  • 持久化缓存重要数据
  1. 批量处理操作
  • DOM操作批量更新
  • 网络请求合并
  • 状态更新合并
  1. 避免阻塞主线程
  • 长时间任务使用Web Worker
  • 复杂计算使用时间切片
  • 避免同步的阻塞操作
11.2 手写实现的优势
  1. 精细控制
  • 可以根据具体需求定制优化策略
  • 避免通用库的冗余代码
  1. 更好的理解
  • 深入理解性能问题的本质
  • 掌握底层优化原理
  1. 更小的包体积
  • 只包含需要的功能
  • 避免依赖大型库
  1. 更好的可调试性
  • 完全控制代码流程
  • 更容易添加日志和监控
11.3 持续优化流程
  1. 建立性能文化
  • 性能作为核心需求
  • 定期性能评审
  • 性能回归测试
  1. 自动化性能测试
  • 集成到CI/CD流程
  • 自动生成性能报告
  • 设置性能预算
  1. 渐进式优化
  • 从最关键的问题开始
  • 小步快跑,持续改进
  • 监控优化效果
  1. 知识分享与传承
  • 建立性能知识库
  • 定期分享会
  • 编写优化指南

总结

JavaScript性能优化是一个持续的过程,需要结合理论知识、实践经验和工具支持。通过手写实现这些优化技术,我们不仅能够解决具体的性能问题,更能深入理解性能优化的本质。

记住,最好的优化往往是那些能够从根本上解决问题的优化,而不是临时的修补。始终以用户体验为中心,以数据为依据,以持续改进为方法,才能构建出真正高性能的Web应用。

性能优化没有银弹,但有了这些手写实现的技术储备,你将能够更自信地面对各种性能挑战,构建出更快、更流畅的用户体验。

前端常用模式:提升代码质量的四大核心模式

引言

在前端开发中,随着应用复杂度不断增加,代码的组织和管理变得越来越重要。本文将深入探讨前端开发中四种极其有用的模式:中间件模式、管道模式、链式调用和惰性加载。这些模式不仅能提高代码的可读性和可维护性,还能显著优化应用性能。

一、中间件模式(Middleware Pattern)

中间件模式允许我们在请求和响应的处理流程中插入多个处理阶段, 这种模式在Node.js框架(例如Koa、Express)中广泛应用, 但在前端同样有其用武之地。

1.1 核心概念

中间件本质上是一个函数, 它可以:

  • 访问请求(request)和响应(response)对象
  • 执行任何代码
  • 修改请求和响应对象
  • 结束请求-响应周期
  • 调用下一个中间件
1.2 基础实现
// 简单中间件系统实现
class MiddlewareSystem {
  constructor() {
    this.middlewares = [];
    this.context = {};
  }

  // 添加中间件
  use(middleware) {
    if (typeof middleware !== 'function') {
      throw new Error('Middleware must be a function');
    }
    this.middlewares.push(middleware);
    return this; // 支持链式调用
  }

  // 执行中间件
  async run(input) {
    this.context = { ...input };
    
    // 创建next函数
    let index = 0;
    const next = async () => {
      if (index < this.middlewares.length) {
        const middleware = this.middlewares[index++];
        await middleware(this.context, next);
      }
    };
    
    try {
      await next();
      return this.context;
    } catch (error) {
      console.error('Middleware execution error:', error);
      throw error;
    }
  }
}

// 使用示例
const system = new MiddlewareSystem();

// 添加中间件
system
  .use(async (ctx, next) => {
    console.log('Middleware 1: Start');
    ctx.timestamp = Date.now();
    await next();
    console.log('Middleware 1: End');
  })
  .use(async (ctx, next) => {
    console.log('Middleware 2: Start');
    ctx.user = { id: 1, name: 'John' };
    // 模拟异步操作
    await new Promise(resolve => setTimeout(resolve, 100));
    await next();
    console.log('Middleware 2: End');
  })
  .use(async (ctx, next) => {
    console.log('Middleware 3: Start');
    ctx.data = { message: 'Hello World' };
    // 不再调用next(),结束执行
    console.log('Middleware 3: End (no next call)');
  });

// 运行中间件
system.run({ requestId: '123' }).then(result => {
  console.log('Final context:', result);
});
1.3 错误处理中间件
class ErrorHandlingMiddleware {
  constructor() {
    this.middlewares = [];
    this.errorMiddlewares = [];
  }

  use(middleware) {
    this.middlewares.push(middleware);
    return this;
  }

  useError(errorMiddleware) {
    this.errorMiddlewares.push(errorMiddleware);
    return this;
  }

  async run(input) {
    const context = { ...input };
    let index = 0;
    let errorIndex = 0;
    let error = null;

    const next = async (err) => {
      if (err) {
        error = err;
        errorIndex = 0;
        return await nextError();
      }

      if (index < this.middlewares.length) {
        const middleware = this.middlewares[index++];
        try {
          await middleware(context, next);
        } catch (err) {
          await next(err);
        }
      }
    };

    const nextError = async () => {
      if (errorIndex < this.errorMiddlewares.length) {
        const errorMiddleware = this.errorMiddlewares[errorIndex++];
        try {
          await errorMiddleware(error, context, nextError);
        } catch (err) {
          error = err;
          await nextError();
        }
      }
    };

    await next();
    return { context, error };
  }
}

// 使用示例
const errorSystem = new ErrorHandlingMiddleware();

errorSystem
  .use(async (ctx, next) => {
    console.log('Processing...');
    // 模拟错误
    if (!ctx.user) {
      throw new Error('User not found');
    }
    await next();
  })
  .useError(async (err, ctx, next) => {
    console.error('Error caught:', err.message);
    ctx.error = err.message;
    ctx.status = 'error';
    await next();
  });

errorSystem.run({}).then(result => {
  console.log('Result with error handling:', result);
});
1.4 前端应用场景
// 前端请求拦截中间件
class RequestInterceptor {
  constructor() {
    this.interceptors = [];
    this.defaultConfig = {
      timeout: 5000,
      headers: {}
    };
  }

  use(interceptor) {
    this.interceptors.push(interceptor);
    return this;
  }

  async request(url, config = {}) {
    const context = {
      url,
      config: { ...this.defaultConfig, ...config },
      response: null,
      error: null
    };

    let index = 0;
    const next = async () => {
      if (index < this.interceptors.length) {
        const interceptor = this.interceptors[index++];
        await interceptor(context, next);
      } else {
        // 执行实际请求
        await this.executeRequest(context);
      }
    };

    await next();
    return context;
  }

  async executeRequest(context) {
    try {
      const response = await fetch(context.url, context.config);
      context.response = await response.json();
    } catch (error) {
      context.error = error;
    }
  }
}

// 创建请求拦截器
const api = new RequestInterceptor();

api
  .use(async (ctx, next) => {
    console.log('Auth interceptor');
    ctx.config.headers.Authorization = `Bearer ${localStorage.getItem('token')}`;
    await next();
  })
  .use(async (ctx, next) => {
    console.log('Logging interceptor');
    console.log(`Request to ${ctx.url}`, ctx.config);
    const start = Date.now();
    await next();
    const duration = Date.now() - start;
    console.log(`Request completed in ${duration}ms`);
  })
  .use(async (ctx, next) => {
    console.log('Cache interceptor');
    const cacheKey = `cache_${ctx.url}`;
    const cached = localStorage.getItem(cacheKey);
    
    if (cached && !ctx.config.noCache) {
      ctx.response = JSON.parse(cached);
      console.log('Using cached response');
    } else {
      await next();
      if (ctx.response && !ctx.error) {
        localStorage.setItem(cacheKey, JSON.stringify(ctx.response));
      }
    }
  });

// 使用拦截器
api.request('https://api.example.com/data', { method: 'GET' })
  .then(result => console.log('Response:', result.response));

二、管道模式(Pipeline Pattern)

管道模式将多个处理函数连接起来, 数据像流水一样经过这些函数进行处理和转换。

2.1 基本实现
// 同步管道
const pipeline = (...fns) => (initialValue) => {
  return fns.reduce((value, fn) => {
    if (typeof fn !== 'function') {
      throw new Error(`Pipeline expects functions, got ${typeof fn}`);
    }
    return fn(value);
  }, initialValue);
};

// 异步管道
const asyncPipeline = (...fns) => async (initialValue) => {
  let result = initialValue;
  for (const fn of fns) {
    if (typeof fn !== 'function') {
      throw new Error(`Pipeline expects functions, got ${typeof fn}`);
    }
    result = await fn(result);
  }
  return result;
};

// 可中断的管道
const breakablePipeline = (...fns) => (initialValue) => {
  let shouldBreak = false;
  let breakValue = null;
  
  const breakFn = (value) => {
    shouldBreak = true;
    breakValue = value;
  };
  
  const result = fns.reduce((value, fn) => {
    if (shouldBreak) return breakValue;
    return fn(value, breakFn);
  }, initialValue);
  
  return shouldBreak ? breakValue : result;
};
2.2 数据处理管道示例
// 数据清洗管道
const dataCleaningPipeline = pipeline(
  // 1. 移除空值
  (data) => data.filter(item => item != null),
  
  // 2. 标准化字段
  (data) => data.map(item => ({
    ...item,
    name: item.name?.trim().toLowerCase() || 'unknown',
    value: Number(item.value) || 0
  })),
  
  // 3. 去重
  (data) => {
    const seen = new Set();
    return data.filter(item => {
      const key = `${item.name}-${item.value}`;
      if (seen.has(key)) return false;
      seen.add(key);
      return true;
    });
  },
  
  // 4. 排序
  (data) => data.sort((a, b) => b.value - a.value),
  
  // 5. 限制数量
  (data) => data.slice(0, 10)
);

// 使用管道
const rawData = [
  { name: '  John  ', value: '100' },
  { name: 'Jane', value: 200 },
  null,
  { name: 'John', value: '100' }, // 重复
  { name: '', value: 'invalid' }
];

const cleanedData = dataCleaningPipeline(rawData);
console.log('Cleaned data:', cleanedData);
2.3 表单验证管道
// 验证规则
const validators = {
  required: (value) => ({
    isValid: value != null && value.toString().trim() !== '',
    message: 'This field is required'
  }),
  
  minLength: (min) => (value) => ({
    isValid: value?.toString().length >= min,
    message: `Minimum length is ${min} characters`
  }),
  
  maxLength: (max) => (value) => ({
    isValid: value?.toString().length <= max,
    message: `Maximum length is ${max} characters`
  }),
  
  email: (value) => ({
    isValid: /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value),
    message: 'Invalid email format'
  }),
  
  numeric: (value) => ({
    isValid: !isNaN(parseFloat(value)) && isFinite(value),
    message: 'Must be a number'
  })
};

// 表单验证管道
class FormValidator {
  constructor(rules) {
    this.rules = rules;
  }

  validate(data) {
    const errors = {};
    const results = {};

    for (const [field, fieldRules] of Object.entries(this.rules)) {
      const value = data[field];
      const fieldErrors = [];

      for (const rule of fieldRules) {
        const result = rule(value);
        if (!result.isValid) {
          fieldErrors.push(result.message);
        }
      }

      if (fieldErrors.length > 0) {
        errors[field] = fieldErrors;
      } else {
        results[field] = value;
      }
    }

    return {
      isValid: Object.keys(errors).length === 0,
      errors,
      results
    };
  }
}

// 使用示例
const registrationRules = {
  username: [
    validators.required,
    validators.minLength(3),
    validators.maxLength(20)
  ],
  email: [
    validators.required,
    validators.email
  ],
  age: [
    validators.required,
    validators.numeric,
    (value) => ({
      isValid: value >= 18 && value <= 100,
      message: 'Age must be between 18 and 100'
    })
  ]
};

const validator = new FormValidator(registrationRules);
const userData = {
  username: 'johndoe',
  email: 'john@example.com',
  age: 25
};

const validationResult = validator.validate(userData);
console.log('Validation result:', validationResult);

三、链式调用(Chaining Pattern)

链式调用通过返回对象实例本身(this), 允许连续调用多个方法, 使代码更加流畅易读。

3.1 基础链式调用
// jQuery风格的链式调用
class QueryBuilder {
  constructor() {
    this.query = {
      select: [],
      from: null,
      where: [],
      orderBy: [],
      limit: null,
      offset: null
    };
  }

  select(...fields) {
    this.query.select.push(...fields);
    return this;
  }

  from(table) {
    this.query.from = table;
    return this;
  }

  where(condition) {
    this.query.where.push(condition);
    return this;
  }

  orderBy(field, direction = 'ASC') {
    this.query.orderBy.push({ field, direction });
    return this;
  }

  limit(count) {
    this.query.limit = count;
    return this;
  }

  offset(count) {
    this.query.offset = count;
    return this;
  }

  build() {
    const { select, from, where, orderBy, limit, offset } = this.query;
    
    if (!from) {
      throw new Error('FROM clause is required');
    }

    let sql = `SELECT ${select.length > 0 ? select.join(', ') : '*'} FROM ${from}`;
    
    if (where.length > 0) {
      sql += ` WHERE ${where.join(' AND ')}`;
    }
    
    if (orderBy.length > 0) {
      const orderClauses = orderBy.map(({ field, direction }) => `${field} ${direction}`);
      sql += ` ORDER BY ${orderClauses.join(', ')}`;
    }
    
    if (limit !== null) {
      sql += ` LIMIT ${limit}`;
    }
    
    if (offset !== null) {
      sql += ` OFFSET ${offset}`;
    }
    
    return sql + ';';
  }

  reset() {
    this.query = {
      select: [],
      from: null,
      where: [],
      orderBy: [],
      limit: null,
      offset: null
    };
    return this;
  }
}

// 使用示例
const sql = new QueryBuilder()
  .select('id', 'name', 'email')
  .from('users')
  .where('active = true')
  .where('age >= 18')
  .orderBy('name', 'ASC')
  .limit(10)
  .offset(0)
  .build();

console.log('Generated SQL:', sql);
3.2 DOM操作链式调用
class DOMElement {
  constructor(selector) {
    if (typeof selector === 'string') {
      this.elements = Array.from(document.querySelectorAll(selector));
    } else if (selector instanceof Element) {
      this.elements = [selector];
    } else if (Array.isArray(selector)) {
      this.elements = selector;
    } else {
      this.elements = [];
    }
  }

  // CSS相关方法
  css(property, value) {
    if (typeof property === 'object') {
      this.elements.forEach(el => {
        Object.assign(el.style, property);
      });
    } else if (value !== undefined) {
      this.elements.forEach(el => {
        el.style[property] = value;
      });
    }
    return this;
  }

  addClass(className) {
    this.elements.forEach(el => {
      el.classList.add(className);
    });
    return this;
  }

  removeClass(className) {
    this.elements.forEach(el => {
      el.classList.remove(className);
    });
    return this;
  }

  toggleClass(className) {
    this.elements.forEach(el => {
      el.classList.toggle(className);
    });
    return this;
  }

  // 内容操作
  text(content) {
    if (content !== undefined) {
      this.elements.forEach(el => {
        el.textContent = content;
      });
      return this;
    }
    return this.elements[0]?.textContent || '';
  }

  html(content) {
    if (content !== undefined) {
      this.elements.forEach(el => {
        el.innerHTML = content;
      });
      return this;
    }
    return this.elements[0]?.innerHTML || '';
  }

  // 属性操作
  attr(name, value) {
    if (value !== undefined) {
      this.elements.forEach(el => {
        el.setAttribute(name, value);
      });
      return this;
    }
    return this.elements[0]?.getAttribute(name) || null;
  }

  // 事件处理
  on(event, handler, options = {}) {
    this.elements.forEach(el => {
      el.addEventListener(event, handler, options);
    });
    return this;
  }

  off(event, handler, options = {}) {
    this.elements.forEach(el => {
      el.removeEventListener(event, handler, options);
    });
    return this;
  }

  // 遍历
  each(callback) {
    this.elements.forEach((el, index) => {
      callback.call(el, index, el);
    });
    return this;
  }

  // 查找子元素
  find(selector) {
    const found = [];
    this.elements.forEach(el => {
      found.push(...Array.from(el.querySelectorAll(selector)));
    });
    return new DOMElement(found);
  }

  // 获取父元素
  parent() {
    const parents = this.elements.map(el => el.parentElement);
    return new DOMElement(parents.filter(Boolean));
  }

  // 显示/隐藏
  show() {
    return this.css('display', '');
  }

  hide() {
    return this.css('display', 'none');
  }

  // 动画
  animate(properties, duration = 300, easing = 'ease') {
    this.elements.forEach(el => {
      el.style.transition = `all ${duration}ms ${easing}`;
      Object.assign(el.style, properties);
      
      setTimeout(() => {
        el.style.transition = '';
      }, duration);
    });
    return this;
  }
}

// 使用示例
// 假设HTML中有: <div id="myDiv">Hello</div>
const $ = (selector) => new DOMElement(selector);

$('#myDiv')
  .css({
    color: 'white',
    backgroundColor: 'blue',
    padding: '10px'
  })
  .addClass('highlight')
  .text('Hello, World!')
  .on('click', function() {
    $(this).toggleClass('active');
  })
  .animate({
    opacity: 0.8,
    transform: 'scale(1.1)'
  }, 300);
3.3 构建器模式与链式调用
// 配置对象构建器
class ConfigurationBuilder {
  constructor() {
    this.config = {
      api: {},
      ui: {},
      features: {},
      performance: {}
    };
  }

  // API配置
  withApi(baseUrl) {
    this.config.api.baseUrl = baseUrl;
    return this;
  }

  withApiVersion(version) {
    this.config.api.version = version;
    return this;
  }

  withTimeout(ms) {
    this.config.api.timeout = ms;
    return this;
  }

  // UI配置
  withTheme(theme) {
    this.config.ui.theme = theme;
    return this;
  }

  withLanguage(lang) {
    this.config.ui.language = lang;
    return this;
  }

  withDarkMode(enabled) {
    this.config.ui.darkMode = enabled;
    return this;
  }

  // 功能配置
  enableFeature(feature) {
    this.config.features[feature] = true;
    return this;
  }

  disableFeature(feature) {
    this.config.features[feature] = false;
    return this;
  }

  // 性能配置
  withCache(enabled) {
    this.config.performance.cache = enabled;
    return this;
  }

  withLazyLoad(enabled) {
    this.config.performance.lazyLoad = enabled;
    return this;
  }

  withCompression(enabled) {
    this.config.performance.compression = enabled;
    return this;
  }

  // 构建方法
  build() {
    // 验证配置
    this.validate();
    // 返回不可变配置
    return Object.freeze(JSON.parse(JSON.stringify(this.config)));
  }

  validate() {
    const { api } = this.config;
    if (!api.baseUrl) {
      throw new Error('API base URL is required');
    }
    if (api.timeout && api.timeout < 100) {
      throw new Error('Timeout must be at least 100ms');
    }
  }
}

// 使用示例
const config = new ConfigurationBuilder()
  .withApi('https://api.example.com')
  .withApiVersion('v1')
  .withTimeout(5000)
  .withTheme('dark')
  .withLanguage('en')
  .withDarkMode(true)
  .enableFeature('analytics')
  .enableFeature('notifications')
  .disableFeature('debug')
  .withCache(true)
  .withLazyLoad(true)
  .build();

console.log('App configuration:', config);

四、惰性加载/求值(Lazy Loading/Evaluation)

惰性加载延迟计算或初始化, 直到真正需要时才执行, 可以显著提高应用性能。

4.1 惰性求值实现
// 惰性函数
function lazy(fn) {
  let result;
  let evaluated = false;
  
  return function(...args) {
    if (!evaluated) {
      result = fn.apply(this, args);
      evaluated = true;
    }
    return result;
  };
}

// 惰性属性
function lazyProperty(target, propertyName, getter) {
  let value;
  let evaluated = false;
  
  Object.defineProperty(target, propertyName, {
    get() {
      if (!evaluated) {
        value = getter.call(this);
        evaluated = true;
      }
      return value;
    },
    enumerable: true,
    configurable: true
  });
}

// 惰性类属性
class LazyClass {
  constructor() {
    this._expensiveData = null;
  }

  get expensiveData() {
    if (this._expensiveData === null) {
      console.log('Computing expensive data...');
      // 模拟耗时计算
      this._expensiveData = this.computeExpensiveData();
    }
    return this._expensiveData;
  }

  computeExpensiveData() {
    // 复杂的计算逻辑
    const start = Date.now();
    let result = 0;
    for (let i = 0; i < 1000000; i++) {
      result += Math.sqrt(i);
    }
    console.log(`Computed in ${Date.now() - start}ms`);
    return result;
  }

  // 重置惰性值
  reset() {
    this._expensiveData = null;
  }
}
4.2 图片懒加载
class LazyImageLoader {
  constructor(options = {}) {
    this.options = {
      root: null,
      rootMargin: '0px',
      threshold: 0.1,
      placeholder: 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7',
      ...options
    };
    
    this.images = new Map();
    this.observer = null;
    this.initObserver();
  }

  initObserver() {
    if ('IntersectionObserver' in window) {
      this.observer = new IntersectionObserver(
        this.handleIntersection.bind(this),
        this.options
      );
    }
  }

  registerImage(imgElement, src) {
    if (!imgElement || !src) return;

    // 保存原始src
    const originalSrc = imgElement.getAttribute('data-src') || src;
    imgElement.setAttribute('data-src', originalSrc);
    
    // 设置占位符
    imgElement.src = this.options.placeholder;
    imgElement.classList.add('lazy-load');
    
    // 添加到观察列表
    this.images.set(imgElement, {
      src: originalSrc,
      loaded: false
    });
    
    if (this.observer) {
      this.observer.observe(imgElement);
    } else {
      // 降级方案:立即加载
      this.loadImage(imgElement);
    }
  }

  handleIntersection(entries) {
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        this.loadImage(img);
        this.observer?.unobserve(img);
      }
    });
  }

  async loadImage(imgElement) {
    const imageData = this.images.get(imgElement);
    if (!imageData || imageData.loaded) return;

    try {
      // 预加载图片
      await this.preloadImage(imageData.src);
      
      // 应用实际图片
      imgElement.src = imageData.src;
      imgElement.classList.remove('lazy-load');
      imgElement.classList.add('lazy-loaded');
      
      imageData.loaded = true;
      
      // 触发加载完成事件
      imgElement.dispatchEvent(new CustomEvent('lazyload', {
        detail: { src: imageData.src }
      }));
    } catch (error) {
      console.error('Failed to load image:', imageData.src, error);
      imgElement.classList.add('lazy-error');
      
      imgElement.dispatchEvent(new CustomEvent('lazyloaderror', {
        detail: { src: imageData.src, error }
      }));
    }
  }

  preloadImage(src) {
    return new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => resolve(img);
      img.onerror = reject;
      img.src = src;
    });
  }

  // 批量注册图片
  registerAll(selector = 'img[data-src]') {
    const images = document.querySelectorAll(selector);
    images.forEach(img => {
      const src = img.getAttribute('data-src');
      if (src) {
        this.registerImage(img, src);
      }
    });
  }

  // 强制加载特定图片
  forceLoad(imgElement) {
    this.loadImage(imgElement);
  }

  // 清理
  destroy() {
    this.observer?.disconnect();
    this.images.clear();
  }
}

// 使用示例
document.addEventListener('DOMContentLoaded', () => {
  const lazyLoader = new LazyImageLoader({
    threshold: 0.5,
    placeholder: '/images/placeholder.png'
  });
  
  // 注册现有图片
  lazyLoader.registerAll();
  
  // 动态添加的图片
  document.addEventListener('newImagesAdded', (event) => {
    const newImages = event.detail.images;
    newImages.forEach(img => {
      lazyLoader.registerImage(img, img.dataset.src);
    });
  });
  
  // 页面离开时清理
  window.addEventListener('beforeunload', () => {
    lazyLoader.destroy();
  });
});
4.3 组件懒加载(Vue/React示例)
// React组件懒加载
import React, { Suspense, lazy } from 'react';

// 懒加载组件
const LazyComponent = lazy(() => import('./ExpensiveComponent'));

// 使用Suspense包裹
function App() {
  return (
    <div>
      <h1>My App</h1>
      <Suspense fallback={<div>Loading...</div>}>
        <LazyComponent />
      </Suspense>
    </div>
  );
}

// Vue组件懒加载
const LazyComponent = () => import('./ExpensiveComponent.vue');

// 路由配置中使用懒加载
const routes = [
  {
    path: '/dashboard',
    component: () => import('./views/Dashboard.vue')
  },
  {
    path: '/settings',
    component: () => import('./views/Settings.vue')
  }
];

// 自定义懒加载封装
function createLazyLoader(importFn, loadingComponent, errorComponent) {
  return {
    data() {
      return {
        component: null,
        error: null,
        loading: true
      };
    },
    
    async created() {
      try {
        const module = await importFn();
        this.component = module.default || module;
      } catch (err) {
        this.error = err;
        console.error('Failed to load component:', err);
      } finally {
        this.loading = false;
      }
    },
    
    render(h) {
      if (this.loading && loadingComponent) {
        return h(loadingComponent);
      }
      
      if (this.error && errorComponent) {
        return h(errorComponent, { error: this.error });
      }
      
      if (this.component) {
        return h(this.component);
      }
      
      return null;
    }
  };
}
4.4 数据懒加载(无限滚动)
class InfiniteScroll {
  constructor(options = {}) {
    this.options = {
      container: document.documentElement,
      distance: 100,
      throttle: 200,
      onLoadMore: () => Promise.resolve(),
      ...options
    };
    
    this.loading = false;
    this.hasMore = true;
    this.throttleTimer = null;
    
    this.init();
  }

  init() {
    this.container = typeof this.options.container === 'string' 
      ? document.querySelector(this.options.container)
      : this.options.container;
    
    if (!this.container) {
      console.error('Container not found');
      return;
    }
    
    this.bindEvents();
  }

  bindEvents() {
    this.container.addEventListener('scroll', this.handleScroll.bind(this));
    window.addEventListener('resize', this.handleScroll.bind(this));
  }

  handleScroll() {
    if (this.throttleTimer) {
      clearTimeout(this.throttleTimer);
    }
    
    this.throttleTimer = setTimeout(() => {
      this.checkPosition();
    }, this.options.throttle);
  }

  checkPosition() {
    if (this.loading || !this.hasMore) return;
    
    const scrollTop = this.container.scrollTop;
    const scrollHeight = this.container.scrollHeight;
    const clientHeight = this.container.clientHeight;
    
    const distanceToBottom = scrollHeight - (scrollTop + clientHeight);
    
    if (distanceToBottom <= this.options.distance) {
      this.loadMore();
    }
  }

  async loadMore() {
    if (this.loading || !this.hasMore) return;
    
    this.loading = true;
    this.container.dispatchEvent(new CustomEvent('loadstart'));
    
    try {
      const result = await this.options.onLoadMore();
      
      if (result && typeof result.hasMore === 'boolean') {
        this.hasMore = result.hasMore;
      }
      
      this.container.dispatchEvent(new CustomEvent('load', { 
        detail: result 
      }));
    } catch (error) {
      this.container.dispatchEvent(new CustomEvent('error', { 
        detail: error 
      }));
      console.error('Failed to load more data:', error);
    } finally {
      this.loading = false;
      this.container.dispatchEvent(new CustomEvent('loadend'));
      
      // 检查是否还需要继续加载(数据可能没有填满屏幕)
      if (this.hasMore) {
        setTimeout(() => this.checkPosition(), 100);
      }
    }
  }

  // 手动触发加载
  triggerLoad() {
    this.loadMore();
  }

  // 重置状态
  reset() {
    this.loading = false;
    this.hasMore = true;
  }

  // 销毁
  destroy() {
    this.container.removeEventListener('scroll', this.handleScroll);
    window.removeEventListener('resize', this.handleScroll);
    
    if (this.throttleTimer) {
      clearTimeout(this.throttleTimer);
    }
  }
}

// 使用示例
const infiniteScroll = new InfiniteScroll({
  container: '#scrollContainer',
  distance: 200,
  throttle: 300,
  async onLoadMore() {
    // 模拟API调用
    const response = await fetch(`/api/items?page=${currentPage}`);
    const data = await response.json();
    
    // 渲染新数据
    renderItems(data.items);
    
    // 返回是否有更多数据
    return { hasMore: data.hasMore };
  }
});

// 动态更新选项
function updateInfiniteScroll(options) {
  infiniteScroll.options = { ...infiniteScroll.options, ...options };
}

五、模式对比与应用场景

模式 优点 缺点 适用场景
中间件模式 解耦、可组合、易于测试 可能增加复杂性、调试困难 请求处理、数据处理管道、插件系统
管道模式 清晰的数据流向、易于测试和复用 可能创建太多小函数、错误处理复杂 数据转换、验证、清洗流程
链式调用 代码流畅、易读、减少临时变量 可能掩盖错误来源、调试困难 构建器模式、DOM操作、配置设置
惰性加载 提高性能】减少内存使用 初始化延迟、复杂性增加 图片加载、组件加载、数据计算
5.1 如何选择模式?
  1. 需要处理请求/响应流程 → 中间件模式
  2. 需要数据转换流水线 → 管道模式
  3. 需要流畅的API接口 → 链式调用
  4. 需要优化性能,延迟初始化 → 惰性加载

六、综合应用实例

6.1 完整的API客户端
class ApiClient {
  constructor(baseURL) {
    this.baseURL = baseURL;
    this.middlewares = [];
    this.defaultHeaders = {
      'Content-Type': 'application/json'
    };
  }

  // 添加中间件
  use(middleware) {
    this.middlewares.push(middleware);
    return this;
  }

  // 创建请求管道
  async request(endpoint, options = {}) {
    const context = {
      url: `${this.baseURL}${endpoint}`,
      options: {
        method: 'GET',
        headers: { ...this.defaultHeaders, ...options.headers },
        ...options
      },
      response: null,
      error: null,
      data: null
    };

    // 执行中间件管道
    await this.executeMiddleware(context);
    
    if (context.error) {
      throw context.error;
    }

    return context.response;
  }

  async executeMiddleware(context) {
    let index = 0;
    const middlewares = this.middlewares;
    
    const next = async () => {
      if (index < middlewares.length) {
        const middleware = middlewares[index++];
        await middleware(context, next);
      } else {
        // 执行实际请求
        await this.executeRequest(context);
      }
    };
    
    await next();
  }

  async executeRequest(context) {
    try {
      const response = await fetch(context.url, context.options);
      context.response = {
        status: response.status,
        headers: Object.fromEntries(response.headers.entries()),
        data: await response.json()
      };
    } catch (error) {
      context.error = error;
    }
  }

  // 快捷方法(链式调用)
  get(endpoint, options = {}) {
    return this.request(endpoint, { ...options, method: 'GET' });
  }

  post(endpoint, data, options = {}) {
    return this.request(endpoint, {
      ...options,
      method: 'POST',
      body: JSON.stringify(data)
    });
  }

  put(endpoint, data, options = {}) {
    return this.request(endpoint, {
      ...options,
      method: 'PUT',
      body: JSON.stringify(data)
    });
  }

  delete(endpoint, options = {}) {
    return this.request(endpoint, { ...options, method: 'DELETE' });
  }
}

// 创建API客户端并配置中间件
const api = new ApiClient('https://api.example.com')
  .use(async (ctx, next) => {
    // 认证中间件
    const token = localStorage.getItem('auth_token');
    if (token) {
      ctx.options.headers.Authorization = `Bearer ${token}`;
    }
    await next();
  })
  .use(async (ctx, next) => {
    // 日志中间件
    console.log(`[API] ${ctx.options.method} ${ctx.url}`);
    const start = Date.now();
    await next();
    const duration = Date.now() - start;
    console.log(`[API] Completed in ${duration}ms`);
  })
  .use(async (ctx, next) => {
    // 错误处理中间件
    try {
      await next();
    } catch (error) {
      console.error('[API] Request failed:', error);
      // 可以在这里实现重试逻辑
      throw error;
    }
  });

// 使用示例
async function fetchUserData() {
  try {
    const response = await api.get('/users/1');
    console.log('User data:', response.data);
    return response.data;
  } catch (error) {
    console.error('Failed to fetch user:', error);
  }
}
6.2 表单处理系统
class FormProcessor {
  constructor(formElement) {
    this.form = formElement;
    this.fields = new Map();
    this.validators = new Map();
    this.transformers = [];
    this.submitHandlers = [];
    
    this.init();
  }

  init() {
    // 收集表单字段
    Array.from(this.form.elements).forEach(element => {
      if (element.name) {
        this.fields.set(element.name, element);
      }
    });
    
    // 绑定提交事件
    this.form.addEventListener('submit', this.handleSubmit.bind(this));
  }

  // 添加验证器
  addValidator(fieldName, validator) {
    if (!this.validators.has(fieldName)) {
      this.validators.set(fieldName, []);
    }
    this.validators.get(fieldName).push(validator);
    return this;
  }

  // 添加数据转换器
  addTransformer(transformer) {
    this.transformers.push(transformer);
    return this;
  }

  // 添加提交处理器
  onSubmit(handler) {
    this.submitHandlers.push(handler);
    return this;
  }

  // 获取表单数据
  getData() {
    const data = {};
    this.fields.forEach((element, name) => {
      data[name] = this.getValue(element);
    });
    return data;
  }

  getValue(element) {
    if (element.type === 'checkbox') {
      return element.checked;
    } else if (element.type === 'radio') {
      return element.checked ? element.value : null;
    } else if (element.type === 'select-multiple') {
      return Array.from(element.selectedOptions).map(opt => opt.value);
    }
    return element.value;
  }

  // 验证表单
  validate() {
    const errors = {};
    const data = this.getData();
    
    this.validators.forEach((validators, fieldName) => {
      const value = data[fieldName];
      const fieldErrors = [];
      
      validators.forEach(validator => {
        const result = validator(value, data);
        if (result !== true) {
          fieldErrors.push(result || `Validation failed for ${fieldName}`);
        }
      });
      
      if (fieldErrors.length > 0) {
        errors[fieldName] = fieldErrors;
        this.showFieldError(fieldName, fieldErrors[0]);
      } else {
        this.clearFieldError(fieldName);
      }
    });
    
    return {
      isValid: Object.keys(errors).length === 0,
      errors,
      data
    };
  }

  showFieldError(fieldName, message) {
    const field = this.fields.get(fieldName);
    if (field) {
      field.classList.add('error');
      
      let errorElement = field.parentElement.querySelector('.error-message');
      if (!errorElement) {
        errorElement = document.createElement('div');
        errorElement.className = 'error-message';
        field.parentElement.appendChild(errorElement);
      }
      errorElement.textContent = message;
    }
  }

  clearFieldError(fieldName) {
    const field = this.fields.get(fieldName);
    if (field) {
      field.classList.remove('error');
      const errorElement = field.parentElement.querySelector('.error-message');
      if (errorElement) {
        errorElement.remove();
      }
    }
  }

  // 处理提交
  async handleSubmit(event) {
    event.preventDefault();
    
    // 验证
    const validation = this.validate();
    if (!validation.isValid) {
      console.log('Form validation failed:', validation.errors);
      return;
    }
    
    // 数据转换管道
    let processedData = validation.data;
    for (const transformer of this.transformers) {
      processedData = transformer(processedData);
    }
    
    // 执行提交处理器
    for (const handler of this.submitHandlers) {
      try {
        const result = await handler(processedData);
        if (result === false || result?.stopPropagation) {
          break;
        }
      } catch (error) {
        console.error('Submit handler error:', error);
        break;
      }
    }
  }

  // 重置表单
  reset() {
    this.form.reset();
    this.fields.forEach((field, name) => {
      this.clearFieldError(name);
    });
    return this;
  }
}

// 使用示例
const formProcessor = new FormProcessor(document.getElementById('myForm'))
  .addValidator('email', (value) => {
    if (!value) return 'Email is required';
    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
      return 'Invalid email format';
    }
    return true;
  })
  .addValidator('password', (value) => {
    if (!value) return 'Password is required';
    if (value.length < 8) return 'Password must be at least 8 characters';
    return true;
  })
  .addTransformer((data) => {
    // 转换数据
    return {
      ...data,
      email: data.email.toLowerCase().trim(),
      createdAt: new Date().toISOString()
    };
  })
  .onSubmit(async (data) => {
    console.log('Submitting data:', data);
    
    // 模拟API调用
    const response = await fetch('/api/register', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
    
    if (!response.ok) {
      throw new Error('Registration failed');
    }
    
    alert('Registration successful!');
    return true;
  })
  .onSubmit((data) => {
    // 第二个处理器:发送分析事件
    console.log('Analytics event sent for registration');
  });

七、最佳实践与注意事项

7.1 中间件模式最佳实践
  1. 保持中间件简洁单一: 每个中间件只做一件事
  2. 错误处理: 确保中间件有适当的错误处理机制
  3. 性能考虑: 避免在中间件中进行昂贵的同步操作
  4. 顺序很重要: 注意中间件的执行顺序对业务逻辑的影响
7.2 管道模式最佳实践
  1. 纯函数优先: 确保管道中的函数是纯函数,避免副作用
  2. 类型检查: 考虑添加运行时类型检查
  3. 错误处理: 现管道级别的错误处理机制
  4. 性能优化: 考虑使用流式处理大数据集
7.3 链式调用最佳实践
  1. 返回this: 确保每个链式方法都返回实例本身
  2. 不可变操作: 考虑实现不可变版本的链式调用
  3. 清晰的方法名: 方法名应该清晰表达其功能
  4. 文档完善: 链式调用可能隐藏复杂度,需要良好文档
7.4 惰性加载最佳实践
  1. 适度使用: 不要过度使用惰性加载,会增加复杂度
  2. 预加载策略: 对于可能很快需要的内容,考虑预加载
  3. 错误处理: 确保惰性加载失败时有降级方案
  4. 用户反馈: 加载过程中给用户适当的反馈

总结

这四种前端模式-中间件模式、管道模式、链式调用和惰性加载---都是现代前端开发中极其有用的工具。它们各自解决了不同的问题:

  • 中间件模式提供了处理复杂流程的模块化方式
  • 管道模式让数据转换变得清晰和可组合
  • 链式调用创造了流畅、易读的API
  • 惰性加载优化了性能和资源使用

掌握这些模式并知道何时使用它们,将帮助你编写更可维护、更高效的前端代码。记住,设计模式是工具,而不是银弹。根据具体场景选择最合适的模式,并始终以代码清晰性和可维护性为首要考虑。

在实际项目中,这些模式经常组合使用。例如,一个API客户端可能同时使用中间件模式处理请求、管道模式处理数据转换、链式调用提供流畅API,并在适当的地方使用惰性加载优化性能。

希望这篇文章能帮助你在前端开发中更好地应用这些强大的模式!

JavaScript常用设计模式完整指南

引言

设计模式是软件工程中解决常见问题的可复用方案。在JavaScript开发中,合理运用设计模式可以提高代码的可维护性、可扩展性和可读性。本文将详细介绍JavaScript中常用的设计模式及其实现。

一、设计模式分类

设计模式主要分为三大类:

  • 创建型模式: 处理对象创建机制
  • 结构型模式: 处理对象组合和关系
  • 行为型模式: 处理对象间通信和职责分配

二、创建型模式

2.1 单例模式 (Singleton Pattern)

确保一个类只有一个实例, 并提供全局访问点。

// ES6实现
class Singleton {
  constructor() {
    if (Singleton.instance) {
      return Singleton.instance;
    }
    this.data = {};
    Singleton.instance = this;
    return this;
  }

  setData(key, value) {
    this.data[key] = value;
  }

  getData(key) {
    return this.data[key];
  }
}

// 使用示例
const instance1 = new Singleton();
const instance2 = new Singleton();

console.log(instance1 === instance2); // true
instance1.setData('name', 'Singleton');
console.log(instance2.getData('name')); // 'Singleton'

// 闭包实现
const SingletonClosure = (function() {
  let instance;
  
  function createInstance() {
    const object = { data: {} };
    return {
      setData: (key, value) => object.data[key] = value,
      getData: (key) => object.data[key]
    };
  }
  
  return {
    getInstance: function() {
      if (!instance) {
        instance = createInstance();
      }
      return instance;
    }
  };
})();
2.2 工厂模式 (Factory Pattern)

创建对象而不暴露创建逻辑, 通过一个公共接口创建对象。

// 简单工厂模式
class Car {
  constructor(options) {
    this.type = options.type || 'sedan';
    this.color = options.color || 'white';
    this.price = options.price || 20000;
  }
}

class Truck {
  constructor(options) {
    this.type = options.type || 'truck';
    this.color = options.color || 'blue';
    this.price = options.price || 50000;
    this.capacity = options.capacity || '5t';
  }
}

class VehicleFactory {
  static createVehicle(type, options) {
    switch (type) {
      case 'car':
        return new Car(options);
      case 'truck':
        return new Truck(options);
      default:
        throw new Error('Unknown vehicle type');
    }
  }
}

// 使用示例
const myCar = VehicleFactory.createVehicle('car', {
  color: 'red',
  price: 25000
});

const myTruck = VehicleFactory.createVehicle('truck', {
  color: 'black',
  capacity: '10t'
});

// 工厂方法模式
class Vehicle {
  drive() {
    console.log(`${this.type} is driving`);
  }
}

class Car2 extends Vehicle {
  constructor() {
    super();
    this.type = 'Car';
  }
}

class Truck2 extends Vehicle {
  constructor() {
    super();
    this.type = 'Truck';
  }
}

class VehicleFactory2 {
  createVehicle() {
    throw new Error('This method must be overridden');
  }
}

class CarFactory extends VehicleFactory2 {
  createVehicle() {
    return new Car2();
  }
}

class TruckFactory extends VehicleFactory2 {
  createVehicle() {
    return new Truck2();
  }
}
2.3 建造者模式 (Builder Pattern)

将复杂对象的构建与其表示分离, 使同样的构建过程可以创建不同的表示。

class Pizza {
  constructor() {
    this.size = null;
    this.crust = null;
    this.cheese = false;
    this.pepperoni = false;
    this.mushrooms = false;
    this.onions = false;
  }

  describe() {
    console.log(`Pizza: Size-${this.size}, Crust-${this.crust}, 
      Cheese-${this.cheese}, Pepperoni-${this.pepperoni},
      Mushrooms-${this.mushrooms}, Onions-${this.onions}`);
  }
}

class PizzaBuilder {
  constructor() {
    this.pizza = new Pizza();
  }

  setSize(size) {
    this.pizza.size = size;
    return this;
  }

  setCrust(crust) {
    this.pizza.crust = crust;
    return this;
  }

  addCheese() {
    this.pizza.cheese = true;
    return this;
  }

  addPepperoni() {
    this.pizza.pepperoni = true;
    return this;
  }

  addMushrooms() {
    this.pizza.mushrooms = true;
    return this;
  }

  addOnions() {
    this.pizza.onions = true;
    return this;
  }

  build() {
    return this.pizza;
  }
}

// 使用示例
const pizza = new PizzaBuilder()
  .setSize('large')
  .setCrust('thin')
  .addCheese()
  .addPepperoni()
  .addMushrooms()
  .build();

pizza.describe();
2.4 原型模式 (Prototype Pattern)

通过复制现有对象来创建新对象, 而不是通过实例化类。

// 使用Object.create实现原型模式
const carPrototype = {
  wheels: 4,
  drive() {
    console.log(`${this.brand} is driving with ${this.wheels} wheels`);
  },
  clone() {
    return Object.create(this);
  }
};

// 创建新对象
const tesla = Object.create(carPrototype);
tesla.brand = 'Tesla';
tesla.model = 'Model 3';

const anotherTesla = Object.create(tesla);
anotherTesla.model = 'Model S';

tesla.drive(); // Tesla is driving with 4 wheels
anotherTesla.drive(); // Tesla is driving with 4 wheels

// ES6类实现原型模式
class VehiclePrototype {
  constructor(proto) {
    Object.assign(this, proto);
  }

  clone() {
    return new VehiclePrototype(this);
  }
}

const bikeProto = {
  wheels: 2,
  ride() {
    console.log(`Riding ${this.brand} with ${this.wheels} wheels`);
  }
};

const bike = new VehiclePrototype(bikeProto);
bike.brand = 'Giant';
const anotherBike = bike.clone();
anotherBike.brand = 'Trek';

三、结构型模式

3.1 装饰器模式 (Decorator Pattern)

动态地给对象添加额外职责, 而不改变其结构。

// ES7装饰器语法
function log(target, name, descriptor) {
  const original = descriptor.value;
  
  descriptor.value = function(...args) {
    console.log(`Calling ${name} with`, args);
    const result = original.apply(this, args);
    console.log(`Result: ${result}`);
    return result;
  };
  
  return descriptor;
}

class Calculator {
  @log
  add(a, b) {
    return a + b;
  }
}

// 传统JavaScript实现
class Coffee {
  cost() {
    return 5;
  }
}

class CoffeeDecorator {
  constructor(coffee) {
    this.coffee = coffee;
  }

  cost() {
    return this.coffee.cost();
  }
}

class MilkDecorator extends CoffeeDecorator {
  cost() {
    return this.coffee.cost() + 2;
  }
}

class SugarDecorator extends CoffeeDecorator {
  cost() {
    return this.coffee.cost() + 1;
  }
}

// 使用示例
let myCoffee = new Coffee();
console.log(`Basic coffee: $${myCoffee.cost()}`);

myCoffee = new MilkDecorator(myCoffee);
console.log(`Coffee with milk: $${myCoffee.cost()}`);

myCoffee = new SugarDecorator(myCoffee);
console.log(`Coffee with milk and sugar: $${myCoffee.cost()}`);
3.2 代理模式 (Proxy Pattern)

为其他对象提供一种代理以控制对这个对象的访问。

// ES6 Proxy实现
const target = {
  message: "Hello, World!",
  getMessage() {
    return this.message;
  }
};

const handler = {
  get: function(obj, prop) {
    if (prop === 'message') {
      console.log('Accessing message property');
      return obj[prop] + ' (via proxy)';
    }
    return obj[prop];
  },
  
  set: function(obj, prop, value) {
    if (prop === 'message') {
      console.log(`Setting message to: ${value}`);
      obj[prop] = value;
      return true;
    }
    return false;
  }
};

const proxy = new Proxy(target, handler);

console.log(proxy.message); // "Hello, World! (via proxy)"
proxy.message = "New Message"; // "Setting message to: New Message"

// 保护代理示例
const sensitiveData = {
  username: 'admin',
  password: 'secret123',
  creditCard: '1234-5678-9012-3456'
};

const protectionHandler = {
  get: function(obj, prop) {
    if (prop === 'password' || prop === 'creditCard') {
      return 'Access denied';
    }
    return obj[prop];
  },
  
  set: function(obj, prop, value) {
    if (prop === 'password' || prop === 'creditCard') {
      console.log('Cannot modify sensitive data directly');
      return false;
    }
    obj[prop] = value;
    return true;
  }
};

const protectedData = new Proxy(sensitiveData, protectionHandler);
3.3 适配器模式 (Adapter Pattern)

将一个类的接口转换成客户期望的另一个接口。

// 旧系统接口
class OldSystem {
  specificRequest() {
    return 'Old system response';
  }
}

// 新系统期望的接口
class NewSystem {
  request() {
    return 'New system response';
  }
}

// 适配器
class Adapter {
  constructor(oldSystem) {
    this.oldSystem = oldSystem;
  }

  request() {
    const result = this.oldSystem.specificRequest();
    return `Adapted: ${result}`;
  }
}

// 使用示例
const oldSystem = new OldSystem();
const adapter = new Adapter(oldSystem);

console.log(adapter.request()); // "Adapted: Old system response"

// 实际应用示例:数据格式适配
class JSONData {
  getData() {
    return '{"name": "John", "age": 30}';
  }
}

class XMLData {
  getData() {
    return '<user><name>John</name><age>30</age></user>';
  }
}

class DataAdapter {
  constructor(dataSource) {
    this.dataSource = dataSource;
  }

  getJSON() {
    const data = this.dataSource.getData();
    
    // 如果是XML,转换为JSON
    if (data.startsWith('<')) {
      // 简单转换逻辑
      const nameMatch = data.match(/<name>(.*?)<\/name>/);
      const ageMatch = data.match(/<age>(.*?)<\/age>/);
      
      return JSON.stringify({
        name: nameMatch ? nameMatch[1] : '',
        age: ageMatch ? parseInt(ageMatch[1]) : 0
      });
    }
    
    return data;
  }
}
3.4 外观模式 (Facade Pattern)

为复杂的子系统提供一个统一的简单接口。

// 复杂的子系统
class CPU {
  start() {
    console.log('CPU started');
  }
  
  execute() {
    console.log('CPU executing instructions');
  }
}

class Memory {
  load() {
    console.log('Memory loading data');
  }
}

class HardDrive {
  read() {
    console.log('Hard drive reading data');
  }
}

// 外观
class ComputerFacade {
  constructor() {
    this.cpu = new CPU();
    this.memory = new Memory();
    this.hardDrive = new HardDrive();
  }

  startComputer() {
    console.log('Starting computer...');
    this.cpu.start();
    this.memory.load();
    this.hardDrive.read();
    this.cpu.execute();
    console.log('Computer started successfully');
  }
}

// 使用示例
const computer = new ComputerFacade();
computer.startComputer();

// 另一个例子:DOM操作外观
class DOMFacade {
  constructor(elementId) {
    this.element = document.getElementById(elementId);
  }

  setText(text) {
    this.element.textContent = text;
    return this;
  }

  setStyle(styles) {
    Object.assign(this.element.style, styles);
    return this;
  }

  addClass(className) {
    this.element.classList.add(className);
    return this;
  }

  on(event, handler) {
    this.element.addEventListener(event, handler);
    return this;
  }
}
3.5 组合模式 (Composite Pattern)

将对象组合成树形结构以表示'部分-整体'的层次结构。

// 组件接口
class Component {
  constructor(name) {
    this.name = name;
  }

  add(component) {
    throw new Error('This method must be overridden');
  }

  remove(component) {
    throw new Error('This method must be overridden');
  }

  getChild(index) {
    throw new Error('This method must be overridden');
  }

  operation() {
    throw new Error('This method must be overridden');
  }
}

// 叶子节点
class Leaf extends Component {
  constructor(name) {
    super(name);
  }

  operation() {
    console.log(`Leaf ${this.name} operation`);
  }
}

// 复合节点
class Composite extends Component {
  constructor(name) {
    super(name);
    this.children = [];
  }

  add(component) {
    this.children.push(component);
  }

  remove(component) {
    const index = this.children.indexOf(component);
    if (index > -1) {
      this.children.splice(index, 1);
    }
  }

  getChild(index) {
    return this.children[index];
  }

  operation() {
    console.log(`Composite ${this.name} operation`);
    for (const child of this.children) {
      child.operation();
    }
  }
}

// 使用示例:文件系统
const root = new Composite('root');
const home = new Composite('home');
const user = new Composite('user');

const file1 = new Leaf('file1.txt');
const file2 = new Leaf('file2.txt');
const file3 = new Leaf('file3.txt');

root.add(home);
home.add(user);
user.add(file1);
user.add(file2);
root.add(file3);

root.operation();

四、行为型模式

4.1 策略模式 (Strategy Pattern)

定义一系列算法, 封装每个算法, 并使它们可以互相替换。

// 策略接口
class PaymentStrategy {
  pay(amount) {
    throw new Error('This method must be overridden');
  }
}

// 具体策略
class CreditCardStrategy extends PaymentStrategy {
  constructor(cardNumber, cvv) {
    super();
    this.cardNumber = cardNumber;
    this.cvv = cvv;
  }

  pay(amount) {
    console.log(`Paid $${amount} using Credit Card ${this.cardNumber.slice(-4)}`);
    return true;
  }
}

class PayPalStrategy extends PaymentStrategy {
  constructor(email) {
    super();
    this.email = email;
  }

  pay(amount) {
    console.log(`Paid $${amount} using PayPal (${this.email})`);
    return true;
  }
}

class CryptoStrategy extends PaymentStrategy {
  constructor(walletAddress) {
    super();
    this.walletAddress = walletAddress;
  }

  pay(amount) {
    console.log(`Paid $${amount} using Crypto Wallet ${this.walletAddress.slice(0, 8)}...`);
    return true;
  }
}

// 上下文
class ShoppingCart {
  constructor() {
    this.items = [];
    this.paymentStrategy = null;
  }

  addItem(item, price) {
    this.items.push({ item, price });
  }

  calculateTotal() {
    return this.items.reduce((total, item) => total + item.price, 0);
  }

  setPaymentStrategy(strategy) {
    this.paymentStrategy = strategy;
  }

  checkout() {
    const total = this.calculateTotal();
    if (!this.paymentStrategy) {
      console.log('Please select a payment method');
      return false;
    }
    return this.paymentStrategy.pay(total);
  }
}

// 使用示例
const cart = new ShoppingCart();
cart.addItem('Book', 25);
cart.addItem('Headphones', 100);

cart.setPaymentStrategy(new CreditCardStrategy('1234-5678-9012-3456', '123'));
cart.checkout();

cart.setPaymentStrategy(new PayPalStrategy('user@example.com'));
cart.checkout();
4.2 观察者模式 (Observer Pattern / 发布-订阅模式)

定义对象间的一对多依赖关系, 当一个对象状态改变时, 所有依赖它的对象都会得到通知。

// 发布-订阅实现
class EventEmitter {
  constructor() {
    this.events = {};
  }

  on(event, listener) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(listener);
    return () => this.off(event, listener);
  }

  off(event, listener) {
    if (!this.events[event]) return;
    
    const index = this.events[event].indexOf(listener);
    if (index > -1) {
      this.events[event].splice(index, 1);
    }
  }

  emit(event, ...args) {
    if (!this.events[event]) return;
    
    this.events[event].forEach(listener => {
      try {
        listener.apply(this, args);
      } catch (error) {
        console.error(`Error in event listener for ${event}:`, error);
      }
    });
  }

  once(event, listener) {
    const removeListener = this.on(event, (...args) => {
      listener.apply(this, args);
      removeListener();
    });
    return removeListener;
  }
}

// 使用示例
const emitter = new EventEmitter();

// 订阅事件
const unsubscribe = emitter.on('userLoggedIn', (user) => {
  console.log(`Welcome, ${user.name}!`);
});

emitter.on('userLoggedIn', (user) => {
  console.log(`Sending login notification to ${user.email}`);
});

// 发布事件
emitter.emit('userLoggedIn', { 
  name: 'John Doe', 
  email: 'john@example.com' 
});

// 取消订阅
unsubscribe();

// 观察者模式实现
class Subject {
  constructor() {
    this.observers = [];
  }

  addObserver(observer) {
    this.observers.push(observer);
  }

  removeObserver(observer) {
    const index = this.observers.indexOf(observer);
    if (index > -1) {
      this.observers.splice(index, 1);
    }
  }

  notify(data) {
    this.observers.forEach(observer => observer.update(data));
  }
}

class Observer {
  constructor(name) {
    this.name = name;
  }

  update(data) {
    console.log(`${this.name} received:`, data);
  }
}
4.3 迭代器模式 (Iterator Pattern)

提供一种方法顺序访问聚合对象中的各个元素, 而又不暴露其内部表示。

// 自定义迭代器
class Range {
  constructor(start, end, step = 1) {
    this.start = start;
    this.end = end;
    this.step = step;
  }

  [Symbol.iterator]() {
    let current = this.start;
    const end = this.end;
    const step = this.step;
    
    return {
      next() {
        if (current <= end) {
          const value = current;
          current += step;
          return { value, done: false };
        }
        return { done: true };
      }
    };
  }
}

// 使用示例
for (const num of new Range(1, 5)) {
  console.log(num); // 1, 2, 3, 4, 5
}

// 自定义集合迭代器
class Collection {
  constructor() {
    this.items = [];
  }

  add(item) {
    this.items.push(item);
  }

  [Symbol.iterator]() {
    let index = 0;
    const items = this.items;
    
    return {
      next() {
        if (index < items.length) {
          return { value: items[index++], done: false };
        }
        return { done: true };
      },
      
      return() {
        console.log('Iteration stopped prematurely');
        return { done: true };
      }
    };
  }

  // 生成器实现
  *filter(predicate) {
    for (const item of this.items) {
      if (predicate(item)) {
        yield item;
      }
    }
  }

  *map(transform) {
    for (const item of this.items) {
      yield transform(item);
    }
  }
}
4.4 命令模式 (Command Pattern)

将请求封装为对象, 从而允许参数化客户、队列请求、记录日志以及支持可撤销操作。

// 命令接口
class Command {
  execute() {
    throw new Error('This method must be overridden');
  }

  undo() {
    throw new Error('This method must be overridden');
  }
}

// 具体命令
class LightOnCommand extends Command {
  constructor(light) {
    super();
    this.light = light;
  }

  execute() {
    this.light.turnOn();
  }

  undo() {
    this.light.turnOff();
  }
}

class LightOffCommand extends Command {
  constructor(light) {
    super();
    this.light = light;
  }

  execute() {
    this.light.turnOff();
  }

  undo() {
    this.light.turnOn();
  }
}

// 接收者
class Light {
  constructor(location) {
    this.location = location;
    this.isOn = false;
  }

  turnOn() {
    this.isOn = true;
    console.log(`${this.location} light is ON`);
  }

  turnOff() {
    this.isOn = false;
    console.log(`${this.location} light is OFF`);
  }
}

// 调用者
class RemoteControl {
  constructor() {
    this.commands = [];
    this.history = [];
  }

  setCommand(command) {
    this.commands.push(command);
  }

  executeCommands() {
    this.commands.forEach(command => {
      command.execute();
      this.history.push(command);
    });
    this.commands = [];
  }

  undoLast() {
    if (this.history.length > 0) {
      const lastCommand = this.history.pop();
      lastCommand.undo();
    }
  }
}

// 使用示例
const livingRoomLight = new Light('Living Room');
const kitchenLight = new Light('Kitchen');

const remote = new RemoteControl();

remote.setCommand(new LightOnCommand(livingRoomLight));
remote.setCommand(new LightOnCommand(kitchenLight));
remote.executeCommands();

remote.undoLast();

// 宏命令
class MacroCommand extends Command {
  constructor(commands) {
    super();
    this.commands = commands;
  }

  execute() {
    this.commands.forEach(command => command.execute());
  }

  undo() {
    // 逆序执行撤销
    this.commands.reverse().forEach(command => command.undo());
  }
}
4.5 状态模式 (State Pattern)

允许对象在其内部状态改变时改变其行为, 看起来像是修改了类。

// 状态接口
class TrafficLightState {
  constructor(context) {
    this.context = context;
  }

  change() {
    throw new Error('This method must be overridden');
  }
}

// 具体状态
class RedLightState extends TrafficLightState {
  change() {
    console.log('Red light - STOP');
    this.context.setState(new GreenLightState(this.context));
  }
}

class GreenLightState extends TrafficLightState {
  change() {
    console.log('Green light - GO');
    this.context.setState(new YellowLightState(this.context));
  }
}

class YellowLightState extends TrafficLightState {
  change() {
    console.log('Yellow light - CAUTION');
    this.context.setState(new RedLightState(this.context));
  }
}

// 上下文
class TrafficLight {
  constructor() {
    this.state = new RedLightState(this);
  }

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

  change() {
    this.state.change();
  }
}

// 使用示例
const trafficLight = new TrafficLight();

trafficLight.change(); // Red light - STOP
trafficLight.change(); // Green light - GO
trafficLight.change(); // Yellow light - CAUTION
trafficLight.change(); // Red light - STOP

// 更复杂的例子:文档编辑器状态
class Document {
  constructor() {
    this.state = new DraftState(this);
    this.content = '';
  }

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

  write(text) {
    this.state.write(text);
  }

  publish() {
    this.state.publish();
  }
}

class DraftState {
  constructor(document) {
    this.document = document;
  }

  write(text) {
    this.document.content += text;
    console.log(`Draft: Added "${text}"`);
  }

  publish() {
    console.log('Publishing draft...');
    this.document.setState(new PublishedState(this.document));
  }
}

class PublishedState {
  constructor(document) {
    this.document = document;
  }

  write(text) {
    console.log('Cannot write to published document. Create new draft first.');
  }

  publish() {
    console.log('Document is already published.');
  }
}
4.6 职责链模式 (Chain of Responsibility Pattern)

使多个对象都有机会处理请求, 从而避免请求发送者和接收者之间的耦合关系。

// 处理者接口
class Handler {
  constructor() {
    this.nextHandler = null;
  }

  setNext(handler) {
    this.nextHandler = handler;
    return handler;
  }

  handle(request) {
    if (this.nextHandler) {
      return this.nextHandler.handle(request);
    }
    console.log('No handler found for request:', request);
    return null;
  }
}

// 具体处理者
class AuthenticationHandler extends Handler {
  handle(request) {
    if (request.type === 'auth' && request.credentials === 'valid') {
      console.log('Authentication successful');
      return super.handle(request);
    } else if (request.type === 'auth') {
      console.log('Authentication failed');
      return null;
    }
    return super.handle(request);
  }
}

class AuthorizationHandler extends Handler {
  handle(request) {
    if (request.type === 'auth' && request.role === 'admin') {
      console.log('Authorization granted for admin');
      return super.handle(request);
    } else if (request.type === 'auth') {
      console.log('Authorization denied');
      return null;
    }
    return super.handle(request);
  }
}

class LoggingHandler extends Handler {
  handle(request) {
    console.log(`Logging request: ${JSON.stringify(request)}`);
    return super.handle(request);
  }
}

// 使用示例
const authHandler = new AuthenticationHandler();
const authzHandler = new AuthorizationHandler();
const logHandler = new LoggingHandler();

authHandler
  .setNext(authzHandler)
  .setNext(logHandler);

// 处理请求
const request1 = { type: 'auth', credentials: 'valid', role: 'admin' };
authHandler.handle(request1);

const request2 = { type: 'auth', credentials: 'invalid' };
authHandler.handle(request2);

// 实际应用:请求处理管道
class ValidationHandler extends Handler {
  handle(data) {
    if (!data.email || !data.email.includes('@')) {
      console.log('Validation failed: Invalid email');
      return null;
    }
    console.log('Validation passed');
    return super.handle(data);
  }
}

class SanitizationHandler extends Handler {
  handle(data) {
    data.email = data.email.trim().toLowerCase();
    console.log('Data sanitized');
    return super.handle(data);
  }
}

class SaveHandler extends Handler {
  handle(data) {
    console.log(`Saving data: ${data.email}`);
    return { success: true, id: Date.now() };
  }
}

五、其他重要模式

5.1 模块模式 (Module Pattern)
// 使用IIFE实现模块模式
const UserModule = (function() {
  // 私有变量
  let users = [];
  let userCount = 0;

  // 私有方法
  function generateId() {
    return Date.now().toString(36) + Math.random().toString(36).substr(2);
  }

  // 公共接口
  return {
    addUser: function(name, email) {
      const user = {
        id: generateId(),
        name,
        email,
        createdAt: new Date()
      };
      users.push(user);
      userCount++;
      return user.id;
    },

    getUser: function(id) {
      return users.find(user => user.id === id);
    },

    getUsers: function() {
      return [...users]; // 返回副本
    },

    getUserCount: function() {
      return userCount;
    },

    removeUser: function(id) {
      const index = users.findIndex(user => user.id === id);
      if (index > -1) {
        users.splice(index, 1);
        userCount--;
        return true;
      }
      return false;
    }
  };
})();

// ES6模块语法
export class Calculator {
  static add(a, b) {
    return a + b;
  }

  static multiply(a, b) {
    return a * b;
  }
}
5.2 混入模式 (Mixin Pattern)
// 混入函数
function mixin(target, ...sources) {
  Object.assign(target, ...sources);
  return target;
}

// 可复用的混入对象
const CanEat = {
  eat(food) {
    console.log(`${this.name} is eating ${food}`);
    this.energy += 10;
  }
};

const CanSleep = {
  sleep() {
    console.log(`${this.name} is sleeping`);
    this.energy += 20;
  }
};

const CanPlay = {
  play() {
    console.log(`${this.name} is playing`);
    this.energy -= 5;
  }
};

// 使用混入
class Animal {
  constructor(name) {
    this.name = name;
    this.energy = 100;
  }
}

class Dog extends Animal {
  constructor(name) {
    super(name);
    mixin(this, CanEat, CanSleep, CanPlay);
  }

  bark() {
    console.log(`${this.name} is barking!`);
  }
}

// 使用示例
const dog = new Dog('Rex');
dog.eat('bone');
dog.play();
dog.sleep();
dog.bark();

// ES6类混入
const Flyable = BaseClass => class extends BaseClass {
  fly() {
    console.log(`${this.name} is flying!`);
  }
};

class Bird extends Flyable(Animal) {
  constructor(name) {
    super(name);
  }
}

const bird = new Bird('Tweety');
bird.fly();
5.3 中介者模式 (Mediator Pattern)
// 中介者
class ChatRoom {
  constructor() {
    this.users = new Map();
  }

  register(user) {
    this.users.set(user.name, user);
    user.chatRoom = this;
  }

  send(message, from, to) {
    if (to) {
      // 私聊
      const receiver = this.users.get(to);
      if (receiver) {
        receiver.receive(message, from);
      }
    } else {
      // 群聊
      this.users.forEach(user => {
        if (user.name !== from) {
          user.receive(message, from);
        }
      });
    }
  }
}

// 同事类
class User {
  constructor(name) {
    this.name = name;
    this.chatRoom = null;
  }

  send(message, to = null) {
    this.chatRoom.send(message, this.name, to);
  }

  receive(message, from) {
    console.log(`${from} to ${this.name}: ${message}`);
  }
}

// 使用示例
const chatRoom = new ChatRoom();

const alice = new User('Alice');
const bob = new User('Bob');
const charlie = new User('Charlie');

chatRoom.register(alice);
chatRoom.register(bob);
chatRoom.register(charlie);

alice.send('Hello everyone!');
bob.send('Hi Alice!', 'Alice');
charlie.send('Meeting at 3 PM', 'Alice');

六、总结与最佳实践

何时使用设计模式
  1. 单例模式: 全局配置、日志记录器、数据库连接池
  2. 工厂模式: 创建复杂对象、需要根据条件创建不同对象
  3. 观察者模式: 事件处理系统、实时数据更新
  4. 策略模式: 多种算法实现、需要动态切换行为
  5. 装饰器模式: 动态添加功能、AOP编程
JavaScript设计模式特点
  1. 灵活性: JavaScript的动态特性使得模式实现更加灵活
  2. 函数式特性: 可以利用高阶函数、闭包等特性简化模式实现
  3. 原型继承: 充分利用原型链实现继承和共享方法
  4. ES6+特性: 类语法、Proxy、Symbol、装饰器等增强了模式表达能力
最佳实践建议
  1. 不要过度设计: 只在必要时使用设计模式
  2. 保持简洁: JavaScript本身就很灵活,避免过度复杂的模式实现
  3. 结合语言特性: 充分利用JavaScript的函数式特性
  4. 考虑性能: 某些模式可能带来性能开销,在性能敏感场景要谨慎
  5. 团队共识: 确保团队成员理解所使用的设计模式

设计模式是解决特定问题的工具,而不是银弹。在实际开发中,应根据具体需求选择合适的模式,并灵活调整以适应JavaScript的语言特性。理解模式的核心思想比死记硬背实现方式更重要。

JavaScript 数组原生方法手写实现

引言

在JavaScript开发中,数组方法是日常编码的核心工具。理解这些方法的内部实现原理不仅能帮助我们写出更高效的代码,还能在面试中展现扎实的基础。本文将完整实现JavaScript中最重要、最常用的数组方法,涵盖高阶函数、搜索方法、扁平化方法和排序算法。

一、高阶函数实现

1.1 map方法实现

map是最常用的高阶函数之一,它创建一个新数组,其结果是该数组中的每个元素调用一次提供的函数后的返回值。

Array.prototype.myMap = function (callback, thisArg) {
  // 输入验证
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + "is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;
  const result = new Array(len);

  // 遍历并执行回调
  for (let i = 0; i < len; i++) {
    // 处理稀疏数组
    if (i in obj) {
      result[i] = callback.call(thisArg, obj[i], i, obj);
    }
  }

  return result;
};

// 使用示例
const numbers = [1, 2, 3];
const squares = numbers.myMap((num) => num * num);
console.log(squares); // [1, 4, 9]
1.2 filter方法实现

filter方法创建一个新数组,包含通过测试的所有元素。

Array.prototype.myFilter = function (callback, thisArg) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;
  const result = [];

  for (let i = 0; i < len; i++) {
    if (i in obj) {
      // 如果回调返回true,则保留该元素
      if (callback.call(thisArg, obj[i], i, obj)) {
        result.push(obj[i]);
      }
    }
  }
  return result;
};

// 使用示例:筛选出大于2的数字
const nums = [1, 2, 3, 4, 5];
const filtered = nums.myFilter((num) => num > 2);
console.log(filtered); // [3, 4, 5]
1.3 reduce方法实现

reduce是最强大的高阶函数,可以将数组元素通过reducer函数累积为单个值。

Array.prototype.myReduce = function (callback, initialValue) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;

  // 处理空数组且无初始值的情况
  if (len === 0 && initialValue === undefined) {
    throw new TypeError("Reduce of empty array with no initial value");
  }

  let accumulator = initialValue;
  let startIndex = 0;

  // 如果没有提供初始值,使用第一个有效元素作为初始值
  if (initialValue === undefined) {
    // 找到第一个存在的元素(处理稀疏数组)
    while (startIndex < len && !(startIndex in obj)) {
      startIndex++;
    }

    if (startIndex === len) {
      throw new TypeError("Reduce of empty array with no initial value");
    }

    accumulator = obj[startIndex];
    startIndex++;
  }

  // 执行reduce操作
  for (let i = startIndex; i < len; i++) {
    if (i in obj) {
      accumulator = callback(accumulator, obj[i], i, obj);
    }
  }

  return accumulator;
};

// 使用示例
const sum = [1, 2, 3, 4, 5].myReduce((acc, curr) => acc + curr, 0);
console.log(sum); // 15

// 复杂示例:数组转对象
const items = [
  { id: 1, name: "Apple" },
  { id: 2, name: "Banana" },
  { id: 3, name: "Orange" },
];

const itemMap = items.myReduce((acc, item) => {
  acc[item.id] = item;
  return acc;
}, {});

console.log(itemMap);
// {
//   '1': { id: 1, name: 'Apple' },
//   '2': { id: 2, name: 'Banana' },
//   '3': { id: 3, name: 'Orange' }
// }

二、搜索与断言方法

2.1 find方法实现

find方法返回数组中满足测试函数的第一个元素的值。

Array.prototype.myFind = function (callback, thisArg) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;

  for (let i = 0; i < len; i++) {
    if (i in obj) {
      if (callback.call(thisArg, obj[i], i, obj)) {
        return obj[i];
      }
    }
  }

  return undefined;
};

// 使用示例
const users = [
  { id: 1, name: "Alice", age: 25 },
  { id: 2, name: "Bob", age: 30 },
  { id: 3, name: "Charlie", age: 35 },
];

const user = users.myFind((user) => user.age > 28);
console.log(user); // { id: 2, name: 'Bob', age: 30 }
2.2 findIndex方法实现

findIndex方法返回数组中满足测试函数的第一个元素的索引。

Array.prototype.myFindIndex = function (callback, thisArg) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;

  for (let i = 0; i < len; i++) {
    if (i in obj) {
      if (callback.call(thisArg, obj[i], i, obj)) {
        return i;
      }
    }
  }

  return -1;
};

// 使用示例
const numbers = [5, 12, 8, 130, 44];
const firstLargeNumberIndex = numbers.myFindIndex(num => num > 10);
console.log(firstLargeNumberIndex); // 1
2.3 some方法实现

some方法返回数组中是否至少有一个元素通过了测试。

Array.prototype.mySome = function (callback, thisArg) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;

  for (let i = 0; i < len; i++) {
    if (i in obj) {
      if (callback.call(thisArg, obj[i], i, obj)) {
        return true;
      }
    }
  }

  return false;
};

// 使用示例
const hasEven = [1, 3, 5, 7, 8].mySome((num) => num % 2 === 0);
console.log(hasEven); // true
2.4 every方法实现

every方法测试数组中的所有元素是否都通过了测试。

Array.prototype.myEvery = function (callback, thisArg) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;

  for (let i = 0; i < len; i++) {
    if (i in obj) {
      if (!callback.call(thisArg, obj[i], i, obj)) {
        return false;
      }
    }
  }

  return true;
};

// 使用示例
const allPositive = [1, 2, 3, 4, 5].myEvery((num) => num > 0);
console.log(allPositive); // true

三、数组扁平化方法

3.1 flat方法实现

flat方法创建一个新数组, 其中所有子数组元素递归连接到指定深度。

Array.prototype.myFlat = function (depth = 1) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  // 深度参数验证
  if (depth < 0) {
    throw new RangeError("depth must be a non-negative integer");
  }

  const result = [];

  const flatten = (arr, currentDepth) => {
    for (let i = 0; i < arr.length; i++) {
      const element = arr[i];
      // 如果当前深度小于指定深度且元素是数组, 则递归扁平化
      if (Array.isArray(element) && currentDepth < depth) {
        flatten(element, currentDepth + 1);
      } else {
        // 否则直接添加到结果数组
        // 注意: 如果depth为0,则不会扁平化任何数组
        result.push(element);
      }
    }
  };

  flatten(this, 0);
  return result;
};

// 使用示例
const nestedArray = [1, [2, [3, [4]], 5]];
console.log(nestedArray.myFlat()); // [1, 2, [3, [4]], 5]
console.log(nestedArray.myFlat(2)); // [1, 2, 3, [4], 5]
console.log(nestedArray.myFlat(Infinity)); // [1, 2, 3, 4, 5]
3.2 flatMap方法实现

flatMap方法首先使用映射函数映射每个元素, 然后将结果压缩成一个新数组。

Array.prototype.myFlatMap = function (callback, thisArg) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  if (typeof callback !== "function") {
    throw new TypeError(callback + " is not a function");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;
  const result = [];

  for (let i = 0; i < len; i++) {
    if (i in obj) {
      const mapped = callback.call(thisArg, obj[i], i, obj);

      // 如果回调函数返回的是数组, 则展开它
      if (Array.isArray(mapped)) {
        for (let j = 0; j < mapped.length; j++) {
          result.push(mapped[j]);
        }
      } else {
        // 如果不是数组,直接添加
        result.push(mapped);
      }
    }
  }

  return result;
};

// 使用示例
const phrases = ["Hello world", "JavaScript is awesome"];
const words = phrases.myFlatMap((phrase) => phrase.split(" "));
console.log(words); // ["Hello", "world", "JavaScript", "is", "awesome"]

// 另一个示例:展开并过滤
const numbers2 = [1, 2, 3, 4];
const result = numbers2.myFlatMap((x) => (x % 2 === 0 ? [x, x * 2] : []));
console.log(result); // [2, 4, 4, 8]

四、排序算法实现

4.1 sort方法实现

JavaScript原生的sort方法使用TimSort算法(一种混合排序算法, 结合了归并排序和插入排序)。这里我们实现一个简单但功能完整的排序方法, 支持自定义比较函数。

Array.prototype.mySort = function (compartFn) {
  if (this === null) {
    throw new TypeError("this is null or not defined");
  }

  const obj = Object(this);
  const len = obj.length >>> 0;

  // 如果没有提供比较函数, 使用默认的字符串比较
  if (compartFn === undefined) {
    // 默认比较函数: 将元素转为字符串, 然后比较UTF-16代码单元值序列
    compartFn = function (a, b) {
      const aString = String(a);
      const bString = String(b);

      if (aString < bString) return -1;
      if (aString > bString) return 1;
      return 0;
    };
  } else if (typeof compartFn !== "function") {
    throw new TypeError("compareFn must be a function or undefined");
  }

  // 实现快速排序算法(高效且常用)
  function quickSort(arr, left, right, compare) {
    if (left >= right) return;

    const pivotIndex = partition(arr, left, right, compare);
    quickSort(arr, left, pivotIndex - 1, compare);
    quickSort(arr, pivotIndex + 1, right, compare);
  }

  function partition(arr, left, right, compare) {
    // 选择中间元素作为基准值
    const pivotIndex = Math.floor((left + right) / 2);
    const pivotValue = arr[pivotIndex];

    // 将基准值移到最右边
    [arr[pivotIndex], arr[right]] = [arr[right], arr[pivotIndex]];

    let storeIndex = left;

    for (let i = left; i < right; i++) {
      // 使用比较函数比较当前元素和基准值
      if (compare(arr[i], pivotValue) < 0) {
        [arr[storeIndex], arr[i]] = [arr[i], arr[storeIndex]];
        storeIndex++;
      }
    }

    // 将基准值放到正确的位置
    [arr[storeIndex], arr[right]] = [arr[right], arr[storeIndex]];
    return storeIndex;
  }

  // 将稀疏数组转换为紧凑数组(跳过不存在的元素)
  const compactArray = [];
  for (let i = 0; i < len; i++) {
    if (i in obj) {
      compactArray.push(obj[i]);
    }
  }

  // 执行快速排序
  if (compactArray.length > 0) {
    quickSort(compactArray, 0, compactArray.length - 1, compartFn);
  }

  // 将排序后的数组复制回原数组,保持稀疏性
  let compactIndex = 0;
  for (let i = 0; i < len; i++) {
    if (i in obj) {
      obj[i] = compactArray[compactIndex++];
    }
  }

  return obj;
};

// 使用示例
const unsorted = [3, 1, 4, 1, 5, 9, 2, 6, 5];
unsorted.mySort();
console.log(unsorted); // [1, 1, 2, 3, 4, 5, 5, 6, 9]

// 使用自定义比较函数
const students = [
  { name: "Alice", score: 85 },
  { name: "Bob", score: 92 },
  { name: "Charlie", score: 78 },
];

students.mySort((a, b) => b.score - a.score);
console.log(students);
// 按分数降序排列

五、总结

5.1 实现要点总结
  1. 输入验证: 始终检查this是否为nullundefined, 以及回调函数是否为函数类型
  2. 稀疏数组处理: 使用in操作符检查索引是否存在
  3. 类型安全: 使用>>>0确保长度为非负整数
  4. 性能考虑:
  • 避免不必要的数组拷贝
  • 使用适当的算法(如快速排序对于sort方法)
  • 注意递归深度(特别是对于flat方法)
  1. 与原生方法差异:
  • 我们的实现在某些边缘情况下可能与原生方法略有不同
  • 原生方法通常有更好的性能和内存管理
5.2 实际应用场景
  1. 数据处理: mapfilterreduce是数据处理的三件套
  2. 搜索功能: findfindIndex用于数据检索
  3. 表单验证: someevery用于验证多个输入
  4. 状态管理: flatflatMap在处理嵌套状态时特别有用
  5. 数据展示: sort用于数据排序

通过手动实现这些核心数组方法,我们不仅加深了对JavaScript数组操作的理解,还掌握了函数式编程的核心概念。

记住:在实际生产环境中,仍然建议使用原生数组方法,因为它们经过了充分优化和测试。但理解这些方法的实现原理,将使你成为一个更出色的JavaScript开发者。

❌