您现在的位置是:网站首页 > 频繁操作场景下的模式优化文章详情

频繁操作场景下的模式优化

频繁操作场景下的模式优化

高频触发的事件(如滚动、输入、窗口调整)容易导致性能问题。以搜索框输入为例,每次按键都会触发请求,短时间内产生大量无效调用。这种场景需要特定设计模式平衡响应速度与资源消耗。

防抖模式

防抖的核心在于延迟执行,直到操作停止超过指定时间。适用于连续触发但只需最终结果的场景,比如搜索建议。

function debounce(func, delay) {
  let timer;
  return function(...args) {
    clearTimeout(timer);
    timer = setTimeout(() => {
      func.apply(this, args);
    }, delay);
  };
}

// 实际应用
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', debounce(function() {
  fetchResults(this.value);
}, 300));

高级实现可添加立即执行选项。首次触发立即执行,后续操作进入防抖周期:

function advancedDebounce(func, delay, immediate) {
  let timer;
  return function(...args) {
    const context = this;
    const later = () => {
      timer = null;
      if (!immediate) func.apply(context, args);
    };
    const callNow = immediate && !timer;
    clearTimeout(timer);
    timer = setTimeout(later, delay);
    if (callNow) func.apply(context, args);
  };
}

节流模式

节流通过固定频率执行来限制调用次数。适用于持续触发但需要定期反馈的场景,比如滚动位置计算。

基础时间戳实现:

function throttle(func, limit) {
  let lastRun;
  return function(...args) {
    const now = Date.now();
    if (!lastRun || (now - lastRun >= limit)) {
      func.apply(this, args);
      lastRun = now;
    }
  };
}

定时器增强版保证尾调用执行:

function enhancedThrottle(func, limit) {
  let lastFunc;
  let lastRan;
  return function(...args) {
    const context = this;
    if (!lastRan) {
      func.apply(context, args);
      lastRan = Date.now();
    } else {
      clearTimeout(lastFunc);
      lastFunc = setTimeout(function() {
        if ((Date.now() - lastRan) >= limit) {
          func.apply(context, args);
          lastRan = Date.now();
        }
      }, limit - (Date.now() - lastRan));
    }
  };
}

双模式结合策略

复杂场景可能需要混合策略。比如视频播放器同时处理进度更新和缓冲检测:

function hybridControl(mainAction, secondaryAction, delay) {
  let lastMainCall = 0;
  let pendingSecondary = null;
  
  return function(...args) {
    const now = Date.now();
    
    // 主操作立即执行但限制频率
    if (now - lastMainCall >= delay) {
      mainAction.apply(this, args);
      lastMainCall = now;
    }
    
    // 次要操作防抖处理
    clearTimeout(pendingSecondary);
    pendingSecondary = setTimeout(() => {
      secondaryAction.apply(this, args);
    }, delay * 2);
  };
}

动画帧优化

对于视觉变化操作,requestAnimationFrame 比固定时间间隔更符合浏览器渲染节奏:

function rafThrottle(func) {
  let ticking = false;
  return function(...args) {
    if (!ticking) {
      requestAnimationFrame(() => {
        func.apply(this, args);
        ticking = false;
      });
      ticking = true;
    }
  };
}

// 滚动事件优化
window.addEventListener('scroll', rafThrottle(function() {
  updateParallaxElements();
}));

批量处理模式

当面对大量数据更新时,采用批量提交策略:

class BatchProcessor {
  constructor(processor, batchSize = 50) {
    this.queue = [];
    this.batchSize = batchSize;
    this.processor = processor;
  }

  add(item) {
    this.queue.push(item);
    if (this.queue.length >= this.batchSize) {
      this.flush();
    }
  }

  flush() {
    if (this.queue.length > 0) {
      this.processor([...this.queue]);
      this.queue = [];
    }
  }
}

// 使用示例
const logBatch = new BatchProcessor(items => {
  console.log('Processing batch:', items);
});

for (let i = 0; i < 1000; i++) {
  logBatch.add(i);
}

观察者模式优化

高频事件源使用观察者模式时,通过中间层控制通知频率:

class BufferedObserver {
  constructor(subject, bufferTime) {
    this.subscribers = new Set();
    this.buffer = [];
    this.timer = null;
    
    subject.subscribe(data => {
      this.buffer.push(data);
      if (!this.timer) {
        this.timer = setTimeout(() => {
          this.notifyAll();
          this.timer = null;
        }, bufferTime);
      }
    });
  }

  subscribe(callback) {
    this.subscribers.add(callback);
  }

  notifyAll() {
    if (this.buffer.length > 0) {
      const snapshot = [...this.buffer];
      this.buffer = [];
      this.subscribers.forEach(cb => cb(snapshot));
    }
  }
}

虚拟化处理

对于超长列表渲染,采用虚拟滚动技术:

class VirtualScroller {
  constructor(container, itemHeight, renderItem) {
    this.container = container;
    this.itemHeight = itemHeight;
    this.renderItem = renderItem;
    this.data = [];
    this.visibleItems = [];
    this.scrollTop = 0;
    
    this.container.style.height = `${itemHeight * this.data.length}px`;
    this.viewport = document.createElement('div');
    this.viewport.style.position = 'relative';
    this.viewport.style.height = `${container.clientHeight}px`;
    this.container.appendChild(this.viewport);
    
    this.container.addEventListener('scroll', () => {
      this.handleScroll();
    });
  }

  setData(newData) {
    this.data = newData;
    this.container.style.height = `${this.itemHeight * this.data.length}px`;
    this.updateVisibleItems();
  }

  handleScroll() {
    this.scrollTop = this.container.scrollTop;
    this.updateVisibleItems();
  }

  updateVisibleItems() {
    const startIdx = Math.floor(this.scrollTop / this.itemHeight);
    const endIdx = Math.min(
      startIdx + Math.ceil(this.container.clientHeight / this.itemHeight),
      this.data.length
    );
    
    this.visibleItems = this.data.slice(startIdx, endIdx);
    this.renderViewport(startIdx);
  }

  renderViewport(offset) {
    this.viewport.style.transform = `translateY(${offset * this.itemHeight}px)`;
    this.viewport.innerHTML = '';
    this.visibleItems.forEach((item, i) => {
      const element = this.renderItem(item);
      element.style.position = 'absolute';
      element.style.top = `${i * this.itemHeight}px`;
      this.viewport.appendChild(element);
    });
  }
}

缓存策略优化

高频计算场景引入缓存机制:

function createCachedSelector(selectors, transformer) {
  const cache = new WeakMap();
  
  return function(state) {
    if (!cache.has(state)) {
      const inputs = selectors.map(selector => selector(state));
      cache.set(state, transformer(...inputs));
    }
    return cache.get(state);
  };
}

// 使用示例
const getFilteredUsers = createCachedSelector(
  [state => state.users, state => state.filters],
  (users, filters) => {
    return users.filter(user => 
      filters.every(filter => filter(user))
    );
  }
);

事件委托优化

大量相似元素的事件处理改用事件委托:

document.getElementById('grid-container').addEventListener('click', function(event) {
  const cell = event.target.closest('.grid-cell');
  if (cell) {
    const row = cell.parentNode;
    const colIndex = Array.from(row.children).indexOf(cell);
    const rowIndex = Array.from(this.children).indexOf(row);
    handleCellClick(rowIndex, colIndex, cell);
  }
});

// 替代方案:为每个单元格单独添加监听器
document.querySelectorAll('.grid-cell').forEach(cell => {
  cell.addEventListener('click', function() {
    const row = this.parentNode;
    const colIndex = Array.from(row.children).indexOf(this);
    const rowIndex = Array.from(row.parentNode.children).indexOf(row);
    handleCellClick(rowIndex, colIndex, this);
  });
});

Web Worker 分流

将密集型计算转移到 Web Worker:

// 主线程代码
const worker = new Worker('compute.js');

worker.onmessage = function(e) {
  updateUI(e.data);
};

function requestComputation(data) {
  worker.postMessage(data);
}

// compute.js
self.onmessage = function(e) {
  const result = heavyComputation(e.data);
  self.postMessage(result);
};

function heavyComputation(data) {
  // 复杂计算逻辑
  return processedData;
}

惰性加载模式

资源按需加载优化初始化性能:

class LazyLoader {
  constructor(loader) {
    this.loader = loader;
    this.promise = null;
    this.value = null;
  }

  get() {
    if (this.value !== null) return Promise.resolve(this.value);
    if (this.promise !== null) return this.promise;
    
    this.promise = this.loader().then(val => {
      this.value = val;
      return val;
    });
    
    return this.promise;
  }
}

// 使用示例
const imageLoader = new LazyLoader(() => 
  import('./heavy-image-processor')
);

document.getElementById('process-btn').addEventListener('click', () => {
  imageLoader.get().then(processor => {
    processor.transformImages();
  });
});

增量处理模式

大数据集采用分片处理策略:

async function processInChunks(items, chunkSize, processItem) {
  for (let i = 0; i < items.length; i += chunkSize) {
    const chunk = items.slice(i, i + chunkSize);
    await Promise.all(chunk.map(item => 
      new Promise(resolve => {
        requestIdleCallback(() => {
          processItem(item);
          resolve();
        });
      })
    ));
    
    // 允许主线程响应
    await new Promise(resolve => setTimeout(resolve, 0));
  }
}

// 使用示例
processInChunks(largeDataset, 100, item => {
  renderDataItem(item);
});

状态批处理

React 等框架中的状态批量更新:

class BatchStateUpdater {
  constructor(component) {
    this.component = component;
    this.pendingStates = [];
    this.isBatching = false;
  }

  setState(update) {
    this.pendingStates.push(update);
    
    if (!this.isBatching) {
      this.isBatching = true;
      Promise.resolve().then(() => {
        this.applyUpdates();
        this.isBatching = false;
      });
    }
  }

  applyUpdates() {
    if (this.pendingStates.length > 0) {
      this.component.setState(prevState => 
        this.pendingStates.reduce(
          (state, update) => ({ ...state, ...update }),
          prevState
        )
      );
      this.pendingStates = [];
    }
  }
}

// 在React组件中使用
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.updater = new BatchStateUpdater(this);
  }

  handleMultipleUpdates = () => {
    this.updater.setState({ count: 1 });
    this.updater.setState({ loading: true });
    this.updater.setState({ count: 2 });
    // 最终只触发一次渲染
  };
}

时间切片技术

使用 generator 实现任务分片:

function* taskSlicer(tasks) {
  for (const task of tasks) {
    const start = performance.now();
    yield task();
    
    // 每执行16ms就让出控制权
    if (performance.now() - start > 16) {
      yield;
    }
  }
}

async function runSlicedTasks(tasks) {
  const slicer = taskSlicer(tasks);
  
  function processNext() {
    const { value, done } = slicer.next();
    if (done) return;
    
    Promise.resolve(value).finally(() => {
      requestIdleCallback(processNext);
    });
  }
  
  processNext();
}

// 使用示例
runSlicedTasks([
  () => processLargeDataChunk(0),
  () => processLargeDataChunk(1),
  // ...更多任务
]);

我的名片

网名:~川~

岗位:console.log 调试员

坐标:重庆市-九龙坡区

邮箱:cc@qdcc.cn

沙漏人生

站点信息

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