手写防抖与节流

防抖 – debounce

先知道它做了那些工作:

  1. 是一个函数
  2. 在同一个时间中,再次点击会重新计时,只有一个时间结束才输出数据,然后清空定时器。
<input type="text" id="txt"/>

let txt = document.getElementById('txt')
// 防抖,同一时间内再次触发重新计时,只要最后那一次
function debounce(fn, wait) {
let timer = null

// 除了这个不能是箭头函数,其他都行
return function () {
let self = this,
args = arguments
if (timer) {
clearTimeout(timer)
timer = null
}
timer = setTimeout(() => {
fn.apply(self, args)
}, wait)
}
}

txt.addEventListener('keyup', debounce(e => {
console.log(e.target.value)
}, 2000))

这里可能有些同学比较疑惑,为啥子里面要用一个return来返回函数?

在这里介绍一下我的理解:如果不设置那个 return ,那么在页面上你还没有进行输入,它就会自动执行。嗯,这我也不知道原因是啥,反正测试出来是这样的。有知道的老哥可以留言,学习学习。

还有就是使用 return 返回的函数不能使用箭头函数,这是因为箭头函数的this是指向定义时候的上下文,也就是window了,而且无法更改。而我们是需要 txt 的,所以这里不能设置为箭头函数,其他地方都可以。

节流 – throttle

这两个函数差不多,相差不大,所以疑问都类似,这里就不会做概述了。

先知道它做了那些工作:

  1. 是一个函数
  2. 设置一个时间,函数以这个时间为基准,来取数据,如果没有到达这个时间,则不会重复取数据,只有大于或等于才能取数据。
<input type="text" id="txt" />

let txt = document.getElementById('txt')
// 节流,设置一个时间,然后以该时间为基础进行重复调用,取数据。
function throttle(fn, delay) {
// 知道最初的时间
let preTime = Date.now()

// 除了这个不能是箭头函数,其他都行
return function () {
let self = this,
args = arguments,
// 知道现在的时间
newTime = Date.now()
if (newTime - preTime >= delay) {
fn.apply(self, args)
// 将现在的时变为旧时间
preTime = Date.now()
}
}
}

txt.addEventListener('keyup', throttle(e => {
console.log(e.target.value)
}, 2000))

我们还可以使用定时器的方式实现节流。

// 定时器的方式实现
function throttle(fn, delay) {
let timer = null,
flag = true;
return function () {
let args = arguments
if (!flag) return;
clearTimeout(timer);
flag = false;
timer = setTimeout(() => {
fn.apply(this, args);
flag = true;
}, delay)
}
}

代码汇总

有注释的

<input type="text" id="txt" />

let txt = document.getElementById('txt')
// 防抖,同一时间内再次触发重新计时,只要最后那一次
function debounce(fn, wait) {
let timer = null

// 除了这个不能是箭头函数,其他都行
return function () {
let self = this,
args = arguments
if (timer) {
clearTimeout(timer)
timer = null
}
timer = setTimeout(() => {
fn.apply(self, args)
}, wait)
}
}
// txt.addEventListener('keyup', debounce(e => {
// console.log(e.target.value)
// }, 2000))

// 节流,设置一个时间,然后以该时间为基础进行重复调用,取数据。
function throttle(fn, delay) {
// 知道最初的时间
let preTime = Date.now()

// 除了这个不能是箭头函数,其他都行
return function () {
let self = this,
args = arguments,
// 知道现在的时间
newTime = Date.now()
if (newTime - preTime >= delay) {
fn.apply(self, args)
// 将现在的时变为旧时间
preTime = Date.now()
}
}
}

txt.addEventListener('keyup', throttle(e => {
console.log(e.target.value)
}, 2000))