引言
防抖和节流是针对响应跟不上触发频率这类问题的两种解决方案。
一. 防抖
1.1 防抖是啥
- 比如你写的input的onchange事件,每次改变input里的内容,浏览器都会去服务器索要东西。其实浏览器想要的只是最终你输入的结果,浏览器只想发送一次。防抖的目的就是咋做,使得就发送那最后一次。
1.2 手写防抖
1.2.1基础版
只要0.5秒之内没输入,就向后端发送数据(业务逻辑),执行完一次业务逻辑之后,时间计时器清空,重新开始。
<!DOCTYPE html>
<html lang="en">
<body>
<input id="111" type="text" placeholder="555" />
<script>
let t = null;
let inp = document.getElementById("111");
inp.onchange = function () {
// onchange事件是HTML里input标签支持的表单事件:
// 参考:https://www.w3cschool.cn/htmltags/ref-eventattributes.html
if (t !== null) {
clearTimeout(t);
}
t = setTimeout(() => {
console.log(this.value); //业务逻辑
}, 500); // 0.5秒之内没输入,就执行业务逻辑
};
</script>
</body>
</html>
1.2.2升级版
这里针对防抖进行了一个闭包函数封装
<!DOCTYPE html>
<html lang="en">
<body>
<input id="111" type="text" placeholder="555" />
<script>
let inp = document.getElementById("111");
inp.onchange = debounce(function () {
console.log(this.value); //
}, 500);
//封装一个防抖的闭包函数
function debounce(fn, delay) {
let t = null;// 这个变量会一直在内存中(比如你关闭一个程序,任务管理器中看见该程序内存还有占用就是这种东西)
return function () {
if (t !== null) {
clearTimeout(t);
}
t = setTimeout(() => {
//fn(); // 此时的this指向window ①
fn.call(this); //改变this指向:指向input + 执行业务逻辑 ②
}, delay); // delay毫秒之内没输入,就执行业务逻辑
};
}
</script>
</body>
</html>
①:这里的this指向window—(后边有解析)
②:这里的this指向inp—(后边有解析)
通过A.call(B)使B来调用A,并且立即执行 :A是想被调用的函数,B一般指this,通过call()使inp调用fn()
二. 节流
1.1 节流是啥
- eg:鼠标滚动的时候会触发ajax事件,因为滚动时候的触发的频率太高了,所以我要降低这个触发的频率。这个就是节流
1.2 手写节流
// 节流,这个书写方式和防抖的一样
window.onscroll = throttle(function () {
console.log("节流");
}, 500);
function throttle(fn, delay) {
let flag = true;
return function () {
if (flag) {
setTimeout(() => {
fn.call(this);
flag = true;
}, delay)
}
flag = false;
}
}
三. 知识点
3.1. 改变this指针的三种方式
1、fn.call(obj, 1, 2); // 使obj来调用fn,fn立即执行,传递参数的情形比较少见
2、fn.bind(obj, 1, 2); // 使obj来调用fn,fn不立即执行,传递参数的情形比较少见
3、fn.apply(obj, [1, 2]);//使obj来调用fn,fn立即执行,参数传递是数组的形式,但是实质上还是一个一个传。
3.2. 为什么①的this指向window,②的this指向input
- this指向的规则:谁调用的指向谁。
- 在①里,源头是fn调用产生的,但是fn自己没有this,于是就向上找,就找到了定义debounce时候的window。
- 在②里,通过A.call(B)使B来调用A:此时的B就是inp.onchange,所以此时的this指向inp。
3.3. 附一个我总结的this指向问题解析
- 直接写:指向window
- 方法:对象.方法() 指向对象
- new:var a = new b(this) this指向a
- 箭头函数:指向外一层的 this
3.4. new的时候发生了什么
1、创建一个新对象Obj
2、将新对象(Obj)的_proto_指向构造函数(Person)的prototype对象
3、将构造函数的作用域赋值给新对象 (this指向新创建的对象Obj)
4、执行构造函数中的代码(为这个新对象添加属性)
5、返回新的对象
var Obj = {};
Obj.proto = Person.prototype();
Person.call(Obj);