防抖:
在JavaScript中,防抖(Debounce)是一种编程技巧,用于控制某些函数的执行频率,以确保它们不会因为连续的触发(如快速连续的用户输入、窗口调整大小等事件)而在短时间内被频繁调用。防抖的主要目的是优化性能,减少不必要的计算和 DOM 操作,从而提高应用程序的响应速度和用户体验。
用效果展示一下:
所以说,不管你是点击还是怎样的轻微触碰,都会使页面上的数字疯狂增加,这就像是我们在执行我们页面上的按钮操作一样,页面上的效果一直在不间断的加载,也就是短时间内被频繁调用,这就影响了操作和用户体验,从而有了防抖这个概念。
这里也就是说,dom update < 屏幕更新时间,这就前段问题复杂起来了,在 ajax 发送请求时,耗时的任务 > 触发频率,所以我们在这里来进行前端的性能优化。
防抖的功能
-
提高性能:通过减少不必要的函数调用,降低CPU和内存的使用,尤其是在执行开销较大的函数操作时,如DOM操作、网络请求等,能显著提升应用性能。
-
优化用户体验:对于用户输入、窗口大小调整等场景,防抖可以避免因连续快速的操作导致界面卡顿或频繁更新,提供更平滑的用户体验。
-
节省资源:对于需要访问外部资源(如服务器API调用)的操作,防抖可以减少不必要的网络请求,节约带宽和服务器资源。
-
控制事件响应:在某些情况下,我们可能只关心用户操作的最终状态而非中间过程,比如表单验证、搜索建议的显示,防抖可以帮助我们只在用户停止操作后才执行相应的处理逻辑。
-
减少误操作:对于一些敏感操作,防抖可以防止用户因快速连续点击导致的多次执行,如提交按钮的点击。
所以我们最终的目的是:页面的优化,是我们前端性能优化最重要的点。
使用防抖带来的效果
<div id="container"></div>
<script>
var count = 1;
var container = document.getElementById('container');
// 事件处理函数
function getUserAction() {
container.innerHTML = count++;
}
function debounce (func,wait) {
// 这就是闭包
var timeout
return function() {
// 事件的执行函数 this -> container
// 控制执行次
var context = this
var args = arguments //
clearTimeout(timeout)
// func this -> 普通函数来运行 window
timeout = setTimeout(function() {
func.apply(context,args)
},wait)
}
}
container.onmousemove = debounce(getUserAction,1000)
</script>
这段代码是一个完整的HTML文档,演示了如何使用原生JavaScript实现一个具有防抖(debounce)功能的鼠标移动跟踪器。下面是代码的详细解释和组成部分:
CSS样式
- 内联样式定义了一个ID选择器(
#container),设置了该div的样式属性,如宽度、高度、背景色、字体大小等,使其在页面中突出显示,并且文本居中。
JavaScript脚本
-
变量初始化:
-
count变量初始化为1,用于存储鼠标移动的次数。 -
container变量通过document.getElementById('container')获取页面上的div元素。
-
-
事件处理函数
getUserAction:- 每当该函数被调用时,它会更新
container的内容为当前的count值,并使count自增1。
- 每当该函数被调用时,它会更新
-
防抖函数
debounce:-
这是一个高阶函数,接收一个函数
func和等待时间wait作为参数。 -
它返回一个新的函数,该函数在被连续调用时,只有在最后一次调用后的
wait毫秒内没有再次被调用时,才会执行传入的func。 -
使用了闭包来保存上一次的计时器引用,确保每次调用都能清除前一次的定时器,防止函数被执行多次。
-
利用
apply(context, args)确保在延迟执行时,func的上下文(this)是正确的,虽然在这个特定的例子中,由于getUserAction内部没有直接使用this,这部分并不关键。
-
-
事件绑定:
-
使用DOM Level 0的方式,将
mousemove事件与container元素关联,并将debounce处理后的getUserAction作为事件处理程序。 -
这意味着当鼠标在
container内移动时,getUserAction函数不会立即执行,而是直到鼠标静止超过1000毫秒后,才更新显示计数。
-
这就展示了如何使用JavaScript和防抖技术来提高性能,避免在短时间内因高频触发的事件(如鼠标移动)导致的不必要的函数执行。通过这种方式,页面能够更加高效地响应用户操作,特别是在执行成本较高的操作时。
最后需要注意的点是:
function getUserAction() {
container.innerHTML = count++;
}
- 事件处理函数的主要目的是更新页面上ID为 container 的元素内容,以反映鼠标移动事件触发的计数,也就是说每当 getUserAction 函数被调用,它就会更新页面上指定 div 的内容,显示自从页面加载以来鼠标在该区域移动的累计次数。
function debounce (func,wait) {
// 这就是闭包
var timeout
return function() {
// 事件的执行函数 this -> container
// 控制执行次
var context = this
var args = arguments //
clearTimeout(timeout)
// func this -> 普通函数来运行 window
timeout = setTimeout(function() {
func.apply(context,args)
},wait)
}
}
-
在debounce函数下形成了一个function的闭包函数,其能够访问在其外部定义的timeout变量,就使得每次返回的函数实例都有自己的独立
timeout -
而在之后的时间执行中,分别保存了上下文参数,清除定时器以及设置了新的定时器。而在设置新的定时器中通过apply的显示绑定调用了func函数,改变了this的指向。
惊艳的防抖效果
<body>
<script>
function debounce(func,wait,immediate) {
// 自由变量空间
var timeout ,result
// 真正执行的函数
return function() {
// 二传手
var context = this
var args = arguments
if (timeout) clearTimeout(timeout)
if (immediate) {
var callNow = !timeout
timeout = setTimeout(function() {
timeout = null
},wait)
if(callNow) result = func.apply(context,args)
}else {
timeout = setTimeout(function() {
func.apply(context,args)
},wait)
}
return result
}
}
debounce(getUserAction,1000,true)
</script>
</body>
function debounce(func, wait, immediate) { ... }
-
func: 需要进行防抖处理的实际函数。
-
wait: 防抖的等待时间(毫秒),在此期间若无新的触发,则执行
func。 -
immediate: 布尔值,决定是否立即执行
func至少一次。
这里最主要的区别就是立即执行的逻辑 immediate。就是说:
当immediate为true时,检查是否是第一次调用(!timeout),如果是,则立即执行func并记录返回结果到result。同时,设置一个新的定时器,用于重置timeout,确保后续触发不会立即执行。
否则,遵循传统的防抖逻辑,仅在最后一次调用后的wait毫秒后执行func。
主体思路:
防抖功能函数 为了性能优化 1/60 (屏幕刷新率) 若是函数执行时间大于屏幕刷新时间 ——> 则会卡顿
func 是真正要执行的处理函数, this,args权利来指向
wait 定时器 id clear ,最后一次的设定
immediate 立即执行一次
总结:
这里最主要的体现就是性能的优化,也是我们前端最主要的点。 debounce将执行推到最后一次,把之前的触发全部取消来减少执行的次数。