Interview AiBox logo

Interview AiBox 实时 AI 助手,让你自信应答每一场面试

download免费下载
3local_fire_department36 次面试更新于 2025-08-23account_tree思维导图

请手写一个代码实现

lightbulb

题型摘要

防抖和节流是前端性能优化的两种关键技术。防抖确保函数只在事件停止触发后执行一次,适用于搜索联想等场景;节流确保函数以固定频率执行,适用于滚动事件等场景。两者都通过控制函数执行频率来优化性能,但实现原理和应用场景有所不同。防抖使用延迟执行+重置计时,节流使用固定时间间隔执行。理解它们的原理和实现方式,能帮助我们在实际开发中做出正确的选择。

防抖与节流函数的手写实现

在前端开发中,防抖(Debounce)和节流(Throttle)是两种常用的性能优化技术,用于控制函数的执行频率,特别是在处理频繁触发的事件如resizescrollinput等场景中。

防抖函数(Debounce)

概念与原理

防抖函数的核心思想是:在事件被触发后,等待一定时间间隔后再执行函数,如果在这个时间间隔内事件再次被触发,则重新计时。这样可以确保函数只在用户停止操作后执行一次。

代码实现

/**
 * 防抖函数
 * @param {Function} fn 需要防抖的函数
 * @param {number} delay 延迟时间,单位毫秒
 * @param {boolean} immediate 是否立即执行
 * @return {Function} 防抖后的函数
 */
function debounce(fn, delay = 300, immediate = false) {
  let timer = null;
  let isInvoke = false;
  
  function _debounce(...args) {
    if (timer) clearTimeout(timer);
    
    if (immediate && !isInvoke) {
      fn.apply(this, args);
      isInvoke = true;
    } else {
      timer = setTimeout(() => {
        fn.apply(this, args);
        isInvoke = false;
        timer = null;
      }, delay);
    }
  }
  
  _debounce.cancel = function() {
    if (timer) clearTimeout(timer);
    timer = null;
    isInvoke = false;
  }
  
  return _debounce;
}

应用场景

  • 搜索框输入联想:用户在输入过程中不频繁发送请求,只在停止输入后发送一次请求
  • 按钮点击事件:防止用户多次快速点击导致重复提交
  • 窗口resize事件:窗口调整结束后再执行相关操作

节流函数(Throttle)

概念与原理

节流函数的核心思想是:在一定时间间隔内只执行一次函数,无论这个时间间隔内事件触发了多少次。这样可以确保函数以固定的频率执行。

代码实现

/**
 * 节流函数
 * @param {Function} fn 需要节流的函数
 * @param {number} interval 时间间隔,单位毫秒
 * @param {Object} options 配置项
 * @param {boolean} options.leading 是否在开始时立即执行
 * @param {boolean} options.trailing 是否在结束时执行最后一次
 * @return {Function} 节流后的函数
 */
function throttle(fn, interval = 300, options = { leading: true, trailing: true }) {
  let timer = null;
  let lastTime = 0;
  const { leading, trailing } = options;
  
  function _throttle(...args) {
    const nowTime = Date.now();
    
    // 首次执行或不立即执行的情况
    if (!lastTime && !leading) lastTime = nowTime;
    
    const remainTime = interval - (nowTime - lastTime);
    
    if (remainTime <= 0) {
      if (timer) {
        clearTimeout(timer);
        timer = null;
      }
      
      fn.apply(this, args);
      lastTime = nowTime;
      return;
    }
    
    if (trailing && !timer) {
      timer = setTimeout(() => {
        fn.apply(this, args);
        timer = null;
        lastTime = leading ? Date.now() : 0;
      }, remainTime);
    }
  }
  
  _throttle.cancel = function() {
    if (timer) clearTimeout(timer);
    timer = null;
    lastTime = 0;
  }
  
  return _throttle;
}

应用场景

  • 页面滚动事件:控制滚动事件的触发频率,提高性能
  • 鼠标移动事件:如拖拽、跟随效果等
  • 播放进度条:定期更新播放进度
  • 高频点击事件:限制点击频率

防抖与节流的对比

特性 防抖(Debounce) 节流(Throttle)
执行时机 事件停止触发后一段时间 固定时间间隔内执行一次
执行次数 可能只执行一次 至少执行一次,可能多次
适用场景 只关心最终结果 关心过程和结果
实现原理 延迟执行+重置计时 固定时间间隔执行

使用示例

// 防抖示例:搜索框输入联想
const searchInput = document.getElementById('search');
const searchDebounce = debounce(function(e) {
  console.log('发送搜索请求:', e.target.value);
  // 实际项目中这里可能是API请求
}, 500);

searchInput.addEventListener('input', searchDebounce);

// 节流示例:页面滚动事件
const scrollThrottle = throttle(function() {
  console.log('页面滚动位置:', window.scrollY);
  // 实际项目中这里可能是加载更多内容或更新UI
}, 200);

window.addEventListener('scroll', scrollThrottle);

防抖与节流的可视化理解

--- title: 防抖与节流的执行时机对比 --- gantt dateFormat HH:mm:ss axisFormat %H:%M:%S section 事件触发 事件触发 :a1, 00:00:01, 1s 事件触发 :a2, after a1, 1s 事件触发 :a3, after a2, 1s 事件触发 :a4, after a3, 1s 事件触发 :a5, after a4, 1s 事件触发 :a6, after a5, 1s 事件触发 :a7, after a6, 1s section 防抖(300ms) 函数执行 :b1, after a7, 300ms section 节流(300ms) 函数执行 :c1, after a1, 300ms 函数执行 :c2, after c1, 300ms 函数执行 :c3, after c2, 300ms

实现细节解析

防抖函数实现要点

  1. 使用闭包保存计时器:确保每次调用的是同一个计时器
  2. 清除之前的计时器:每次触发事件时清除之前的计时器,重新计时
  3. 立即执行选项:通过immediate参数控制是否在第一次触发时立即执行
  4. 取消功能:提供cancel方法可以取消待执行的防抖函数

节流函数实现要点

  1. 时间戳判断:通过记录上一次执行的时间戳,判断是否达到执行间隔
  2. 计时器补充:对于最后一次触发,使用计时器确保执行
  3. 首尾执行控制:通过leadingtrailing参数控制是否在开始和结束时执行
  4. 取消功能:提供cancel方法可以取消待执行的节流函数

进阶实现:结合requestAnimationFrame

对于动画相关的场景,可以使用requestAnimationFrame实现更高效的节流函数:

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

// 使用示例
const moveThrottle = rafThrottle(function(e) {
  console.log('鼠标移动:', e.clientX, e.clientY);
});

document.addEventListener('mousemove', moveThrottle);

总结

防抖和节流是前端性能优化的重要手段,它们通过控制函数执行频率来提高应用性能。防抖适合"只关心结果"的场景,如搜索联想;节流适合"关心过程"的场景,如滚动加载。理解它们的原理和实现方式,能够帮助我们在实际开发中做出正确的选择。

参考资料

account_tree

思维导图

Interview AiBox logo

Interview AiBox — 面试搭档

不只是准备,更是实时陪练

Interview AiBox 在面试过程中提供实时屏幕提示、AI 模拟面试和智能复盘,让你每一次回答都更有信心。

AI 助读

一键发送到常用 AI

防抖和节流是前端性能优化的两种关键技术。防抖确保函数只在事件停止触发后执行一次,适用于搜索联想等场景;节流确保函数以固定频率执行,适用于滚动事件等场景。两者都通过控制函数执行频率来优化性能,但实现原理和应用场景有所不同。防抖使用延迟执行+重置计时,节流使用固定时间间隔执行。理解它们的原理和实现方式,能帮助我们在实际开发中做出正确的选择。

智能总结

深度解读

考点定位

思路启发

auto_awesome

相关题目

请做一个自我介绍

自我介绍是面试的开场环节,应遵循"三段式"结构:基本信息与教育背景、核心能力与项目经验、求职动机与个人特质。重点突出与岗位相关的技能和经验,用具体数据和成果支撑,保持真诚自然的表达,控制在2-3分钟内。针对不同公司和岗位进行个性化调整,展示自己的匹配度和价值。

arrow_forward

你有什么问题想问我们公司或团队的吗?

面试结尾提问是展示面试者思考深度和职业素养的重要机会。应提前准备3-5个有深度的问题,围绕团队技术、个人成长、公司文化和业务发展四个方面。好的问题能体现你对公司的了解、对职位的重视以及你的职业规划,避免问基础信息类问题。

arrow_forward

请做一个自我介绍

自我介绍应遵循“我是谁-我为什么能胜任-我为什么想来”的逻辑框架。在“能胜任”部分,要通过STAR法则和量化结果来突出技术亮点和项目经验。在“想来”部分,要表达对华为技术、文化或业务的认同,展现匹配度和诚意。整个过程应简洁有力,控制在1-3分钟内。

arrow_forward

请做一个自我介绍

自我介绍是面试的开场环节,应简洁明了地展示个人基本信息、教育背景、项目经验、技术特长、个人特质和求职动机。优秀的自我介绍应结构清晰、重点突出,与应聘岗位高度匹配,并表达出对公司的了解和加入的强烈意愿。

arrow_forward

请做一个自我介绍,包括你的技术背景、项目经验和学习方向。

自我介绍应包含四个核心部分:个人背景、技术能力、项目经验和学习规划。技术背景需突出前端技术栈掌握程度;项目经验应选择代表性案例,说明技术实现和个人贡献;学习方向要体现职业规划与公司发展的契合度。整体表达应简洁有力,重点突出,时间控制在3-5分钟内。

arrow_forward

阅读状态

阅读时长

6 分钟

阅读进度

6%

章节:17 · 已读:1

当前章节: 防抖函数(Debounce)

最近更新:2025-08-23

本页目录

Interview AiBox logo

Interview AiBox

AI 面试实时助手

面试中屏幕实时显示参考回答,帮你打磨表达。

免费下载download

分享题目

复制链接,或一键分享到常用平台

外部分享