#防抖 #节流 #八股文 两者都可以理解为延时执行,防抖是一段时间内不断的触发只执行最后一次,节流是一段时间内不断触发,会均匀的间隔执行。
举例防抖:一个按钮,不断的点击,1s内点击100次,控制只执行最后一次的点击事件。
举例节流:监听鼠标移动时间,鼠标1s内移动1万次,控制只执行10次,100ms执行一次。
手写防抖函数
JS 保姆级贴心,从零教你手写实现一个防抖debounce方法 - 知乎 (zhihu.com)
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script
src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.js"
type="application/javascript"
></script>
</head>
<body>
<input type="text" class="input" />
<br />
<span class="name"></span>
<script>
const span = document.querySelector('.name')
const input = document.querySelector('.input')
const changeName = function (e) {
console.log(this)
span.innerHTML = e.target.value
}
const debounce = function (fn, wait, immediate) {
// 自由变量,debounce执行完成被释放,time也不会被释放
let time
// 返回一个闭包(...args表示接收剩余的参数)
return function (...args) {
// 保存闭包被调用时的this
const this_ = this
// 清除上一次的定时器
if (time) {
clearInterval(time)
}
if (immediate) {
const action = !time
// 不再是直接执行fn,在内部传递参数
// 箭头函数的this永远指向外层作用域的this
time = setTimeout(function () {
// 通过apply修改fn的this
// 定时器这种回调的执行默认就是指向window,这就导致fn.apply的this也是window,所以你必须得手动将闭包的this存起来赋予给fn,这就是为什么要保存this的缘故。
fn.apply(this_, args)
time = null
}, wait)
if (action) {
fn.apply(this_, args)
}
}
else {
// 不再是直接执行fn,在内部传递参数
time = setTimeout(function () {
// 通过apply修改fn的this
fn.apply(this_, args)
}, wait)
}
}
}
// 通过闭包,得到一个方法
const changeName_ = debounce(changeName, 1000, true)
input.onkeyup = changeName_
</script>
</body>
</html>疑问
JavaScript
// 不防抖
btn.addEventListener('click',function(){
debounce2(getImg, 2000)()
})
// 防抖
btn.onclick = debounce2(getImg, 2000)()为什么呢
防抖2
JavaScript
function debounce (callback, delay = 1000) {
let timer = null;
return function () {
// 因为这里返回出去的方法是被 外部元素调用的,
// 所以这里的 this 就指向了外部元素
let self = this;
// 每个函数内部都一个属性 arguments, 其中包括了所有外部调用这个函数传递进来的参数
let args = arguments;
timer && clearTimeout(timer)
timer = setTimeout(function () {
// apply: 作用就是改变方法内部this的指向, 并能将参数传递给该方法, 最后立即执行这个函数
callback.apply(self, args)
}, delay);
}
}
// 使用
let onInput = document.queryInput('input');
onInput = debounce (function(args){
console.log(this)
console.log(args)
}, 2000)