防抖:多次触发事件后,事件处理函数只执行一次,并且是在触发操作结束时执行。
比如我们需要打印鼠标移动结束后光标的位置时候,我们经常用mousemove函数,但是我们在使用mousemove函数的时候,会打印出几十甚至上百次的鼠标光标的坐标。但是我们实际上需要的只是移动结束后的光标,那么这时候就需要引入防抖函数了。
实现原理:利用定时器,函数第一次执行时设定一个定时器,之后调用时发现已经设定过定时器就清空之前的定时器,并重新设定一个新的定时器,如果存在没有被清空的定时器,当定时器计时结束后触发函数执行。
代码如下:
function debounce(fn, wait = 50) {
// 通过闭包缓存一个定时器 id
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
// 重新设定一个新的定时器
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
节流:触发函数事件后,短时间间隔内无法连续调用,只有上一次函数执行后,过了规定的时间间隔,才能进行下一次的函数调用
简单的实现原理:第一种是用时间戳来判断是否已到执行时间,记录上次执行的时间戳,然后每次触发事件执行回调,回调中判断当前时间戳距离上次执行时间戳的间隔是否已经达到时间差,如果是则执行,并更新上次执行的时间戳,如此循环。
代码如下:
const throttle = (fn, wait = 50) => {
// 上一次执行 fn 的时间
let previous = 0
// 将 throttle 处理结果当作函数返回
return function(...args) {
let now = +new Date()
if (now - previous > wait) {
previous = now
fn.apply(this, args)
}
}
}
关于防抖如果需要第一次就立即执行,可修改为以下:
// immediate 表示第一次是否立即执行
function debounce(fn, wait = 50, immediate) {
let timer = null
return function(...args) {
if (timer) clearTimeout(timer)
// ------ 新增部分 start ------
if (immediate && !timer) {
fn.apply(this, args)
}
// ------ 新增部分 end ------
timer = setTimeout(() => {
fn.apply(this, args)
}, wait)
}
}
其实在使用的时候完全可以用已有的underscore中的方法,但是在学习或者参加面试过程中,防抖跟节流还是比较常问到的知识点,会用不代表你懂,只有理解了,才是自己的。
网友评论