前端性能优化 | 防抖与节流

一. 前言

为什么要做性能优化?性能优化到底有多重要? 性能优是为了提供更好的用户体验加快网站加载速度提高搜索引擎排名节省服务器资源适应多种设备和网络环境等方面的需求。通过不断优化性能,可以提高用户满意度、增加网站流量提高业务效果。

同时性能优化是把双刃剑,有好的一面也有坏的一面。好的一面就是可以能提升网站性能,坏的一面就是配置多,代码复杂,或者要遵守的规则太多。并且某些性能优化规则并不适用所有场景,所以也并不是一味的追求性能优化,而是需要谨慎使用。

防抖和节流JavaScript 中常用的两种性能优化方式。面试中我们也会经常碰到。它们的作用是减少函数的执行次数,以提高代码的性能。本文将详细介绍防抖节流的定义、原理和实现方法,并讨论如何在具体功能中使用它们。

二. 对防抖与节流的理解

什么是防抖(Debounce)

如下图所示,防抖(Debounce)是指在事件被触发 delay 时间后再执行回调 function 函数,如果在这设置的 delay 时间内事件又被触发,则重新计时。这可以使用在些点击请求的事件上,避免因为用户的多次点击向后端发送多次请求。

什么是节流(Throttle)

如下图所示,节流(Throttle)是指规定一个单位时间(延迟 delay 时间),在这个单位时间内,只能有一次触发事件的回调函数执行,如果在同一个单位时间内某事件被触发多次,只有一次能生效。节流可以使用在 scroll 函数的事件监听上,通过事件节流来降低事件调用的频率。

三. 防抖函数的应用场景

  1. 搜索框实时搜索:当用户在搜索框中输入内容时,通常需要实时进行搜索。使用防抖函数可以延迟搜索请求的发送,只在用户停止输入一段时间后才真正发送请求,避免频繁的请求操作。

  2. 表单输入验证:在表单输入过程中,每次用户输入都可能触发验证操作。使用防抖函数可以延迟触发验证操作,只在用户输入完毕一段时间后进行验证,避免频繁的验证操作。

  3. 浏览器窗口调整事件:当用户调整浏览器窗口大小时,会触发resize事件。使用防抖函数可以延迟resize事件的触发,只在用户停止调整窗口一段时间后才执行对应的操作,避免频繁的计算和布局操作。

  4. 鼠标移动事件:在一些特定的交互场景中,需要根据鼠标的移动位置做出相应的交互。使用防抖函数可以延迟鼠标移动事件的触发,只在用户停止移鼠标一段时间后才执行相应的操作,避免过度频繁的操作。

以用户搜索框实时搜索请求后台为例,我们来详细看一下:

原始代码,未进行防抖优化

<div class="box">
  输入事件没有进行防抖处理:<input type="text" id="demo" name="demo">
</div>
<script>
  
  function req(value){
    console.warn("request: " + value + ", time: " + new Date());
  }

  const inputBox = document.getElementById("demo");
  inputBox.addEventListener("keyup",e=>{
    req(e.target.value);
  })
</script>

上面结果所示,只要我们在输入框中每次输入文字,那么就会触发一次模拟请求,这对于用户和开发者而言都是不好的体验和资源的浪费。

思考: 我们想到每次用户输入文字都是需要一定时间的,那么我们可以定义在规定时间进行完整输入才能进行请求,这样我们可以减轻对后台的压力。

使用防抖函数优化后

防抖规则:500ms内输入文字按下键盘都不会触发请求事件,而是在输入框的定时器500ms停止输入后发送请求

优化: 我们改造一下上述的代码,监听我们的输入框,在500ms内连续输入,不进行任何操作,500ms后发送一次请求。

<div class="box">
  输入事件进行防抖处理:<input type="text" id="demo" name="demo">
</div>
<script>
  
  function req(value){
    console.warn("request: " + value + ", time: " + new Date());
  }

  const inputBox = document.getElementById("demo");
  inputBox.addEventListener("keyup",e=>{
    debounce(() => req(e.target.value), 500);
  })
</script>

从上面的运行结果可以看出,在500ms内在输入框中连续输入文字都不会触发请求事件,而是在输入框的定时器500ms停止输入后发送请求。

实现原理很简单,就是对于频繁输入的输入框请求事件添加定时器进行计数,在指定时间内进行频繁输入并不会进行请求,而是在指定时间间隔内停止输入才会执行函数。

当停止输入但在此定时器计数时间内,会重新进行触发请求事件。

四. 节流函数的应用场景

  1. 页面滚动事件:当用户滚动页面时,会频繁触发滚动事件。使用节流函数可以控制滚动事件的触发频率,避免过多的计算和渲染操作,提高页面的性能和流畅度。

  2. 窗口大小调整:当用户调整浏览器窗口大小时,会不断触发resize事件。使用节流函数可以限制resize事件的触发频率,以避免过度计算和布局操作。

  3. 频繁点击按钮:在某些场景下,点击按钮可能会触发重复的提交操作。使用节流函数可以限制按钮点击的触发频率,防止重复的提交。

  4. 动画场景: 避免短时间内多次触发动画引起性能问题

  5. 拖拽场景: 在某些场景下,频繁触发位置变动会造成性能问题,固定时间内只执行一次,防止超高频次触发位置变动

以频繁点击按钮防止重复提交为例子,我们来详细看一下:

原始代码,未进行节流优化

<button id="demo" style="margin: 50px;">点击按钮</button></button>
<script>
    let value = 1
    
    function req(){
        console.warn("request: " + value++ + ", time: " + new Date());
    }
    const ele = document.getElementById("demo");
    ele.addEventListener("click", (e) => {
        req()
    });
</script>

上面结果所示,只要我们点击按钮,那么就会触发一次模拟请求,这除了对于服务器的压力以外,还会造成多次数据提交,有可能会造成数据重复的风险。

使用节流函数优化后

节流规则:1000ms内频繁点击按钮,只能成功一次

优化: 按钮频繁多次点击时,为了避免用户多次请求,做了节流限制,在规定一个1000ms时间内,只能有一次点击成功的触发动作。

<button id="demo" style="margin: 50px;">点击按钮</button></button>
<script>
    let value = 1
    
    function req(){
        console.warn("request: " + value++ + ", time: " + new Date());
    }
    const ele = document.getElementById("demo");
    ele.addEventListener("click", (e) => {
        throttle(() => req(), 1000)
    });
</script>

从上面的运行结果可以看出,在1000ms内按钮连续多次点击,只有一次成功。

五. 实现防抖函数和节流函数

实现防抖函数

实现思路

  1. 定义一个计时器变量,默认为null。

  2. 当事件触发时,清除之前的计时器。

  3. 创建一个新的计时器,延迟执行目标函数。

  4. 在在此时间内,如果再次触了事件,则重复步骤2和3。

  5. 在延迟时间内没有再次触发事件时,执行目标函数。

 * @desc 防抖函数:一定时间内,只有最后一次操作,再过wait毫秒后才执行函数
 * @param {Function} func 函数
 * @param {Number} wait 延迟执行毫秒数
 * @param {Boolean} immediate true 表示立即执行,false 表示非立即执行
 */
let timeout

function debounce(func, wait = 500, immediate = false) {
  
  if (timeout) clearTimeout(timeout)
  
  if (immediate) {
    let callNow = !timeout
    timeout = setTimeout(() => {
      timeout = null
    }, wait)
    if (callNow) typeof func === 'function' && func()
  } else {
    
    timeout = setTimeout(() => {
      typeof func === 'function' && func()
    }, wait)
  }
}


实现节流函数

实现思路

  1. 定义一个标记变量来表示是否允许执行目标函数,默认为0。

  2. 当事件触发时,检查当前的时间戳与标记变量的差值,如果差值大于设定的延迟时间,则执行函数并将标记变量设为当前的时间戳。如果差值小于设定的延迟时间,则不执行。

  3. 在指定时间间隔内再次触发事件时,则重复2步骤。

 * @desc 节流函数:在一定时间内,只能触发一次
 * @param {Function} func 函数
 * @param {Number} wait 延迟执行毫秒数
 */
let previous = 0
function throttle(func, wait = 500) {
  let now = Date.now()
  if (now - previous > wait) {
    typeof func === 'function' && func()
    previous = now
  }
}



总结

在本篇文章中,我们了解了JavaScript中的防抖和节流优化技术。这两种技术都是为了解决频繁触发的事件而产生的性能问题,通过限制事件触发的频率,提升页面性能和用户体验。

我们首先介绍了防抖和节流的定义和区别,防抖是指在一段时间内,只执行最后一次触发的事件,而节流是指一段时间内,固定间隔触发事件。然后,我们详细阐述了防抖和节流的原理和实现方式。

在实际应用中,我们经常遇到需要使用防抖和节流来优化用户交互、滚动事件、输入框输入等场景。通过合理地防抖和节流,我们可以减少冗余的计算和渲染,提高页面的流畅性和响应速度。

在文章的结尾,提供了一些常见的优化库和工具,方便开发者快速应用于实际开发中。

通过本文的学习,希望大家能够充分理解防抖和节流的原理,并且能够根实际情况合理应用于自己的项目,提升页面的性能和用户体验。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Web面试那些事儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值