这是我参与「第四届青训营 」笔记创作活动的第1天
第一次发布笔记,欢迎指正
一、防抖(防止手抖)
场景
现在我们有一个通过监听输入框实时修改名称的需求,如下图
主要问题
修改input的值,对应span标签内的文本就会被修改,但假设我们此时的修改并不是一次innerHTML的更新,而是要将最新的name同步给后端,那么这里就需要发起一次后端请求。抛开请求耗时不说,假设用户在一瞬间增增删删了十余次,此刻你就得发送十多次请求,抛开性能消耗,万一用户网络不好,你甚至还会遇到因调度问题导致数据展示后发先至的bug
解决
当事件被触发的时候,设定一个容错时间延迟执行动作(计时器),若这期间再次被触发,则重新设定周期(清除上一次计时器,重新定时),直到容错时间结束,才触发事件执行动作。代码如下
// 定义防抖函数
const debounce = function (fn, wait) {
// 自由变量,debounce执行完成被释放,time也不会被释放
let time;
// 返回一个闭包
return function () {
// 清除上一次的定时器
if (time) {
clearTimeout(time);
};
// wait时间后执行
time = setTimeout(fn, wait);
}
};
//
const span = document.querySelector('.name');
const input = document.querySelector('.input');
const changeName = function () {
console.log(this);
span.innerHTML = input.value;
};
const changeName_ = debounce(changeName, 3000);
input.onkeyup = changeName_;
附加问题
我们想要这个changeName方法更通用一些,需要让他能够处理参数,我们知道事件可以通过event获取到当前操作的对象target,我们修改changeName为:
const changeName = function (e) {
console.log(this)
span.innerHTML = e.target.value;
};
对应的,我们还要修改防抖代码,实现e的接收
// 定义防抖函数
const debounce = function (fn, wait) {
// 自由变量,debounce执行完成被释放,time也不会被释放
let time;
// 返回一个闭包,接受参数
return function (...args) {
// 清除上一次的定时器
if (time) {
clearTimeout(time);
};
// 不再是直接执行fn,在内部传递参数
time = setTimeout(function () {
fn(...args);
}, wait);
}
};
虽然已经可以用但是有一个细节被忽略,就是this的指向问题,定时器执行后,你会发现changeName的this指向window(非严格模式)
于是再改
const debounce = function (fn, wait) {
// 自由变量,debounce执行完成被释放,time也不会被释放
let time;
// 返回一个闭包,接受参数
return function (...args) {
// 保存闭包被调用时的this
const this_ = this;
// 清除上一次的定时器
if (time) {
clearTimeout(time);
};
// 不再是直接执行fn,在内部传递参数
time = setTimeout(function () {
// 通过apply修改fn的this
fn.apply(this_, args);
}, wait);
}
};
二、节流(节省流量)
场景
现在有一个下图的功能展示
主要问题
滚动的触发是高频的,假如有一个类似这个滚动效果的高频触发事件,我们想要做到的是,让这个触发频率降低。
解决
也就是在固定一段时间内,只执行一次函数,若这段时间有新事件触发,则选择不执行。当这段时间结束后,又有事件触发,才再次开始一段「保护期」。代码如下:
const throttle = (fn, wait) => {
let time;
return function (...args) {
const this_ = this;
// 如果存在time则不创建新的定时器
if (!time) {
time = setTimeout(() => {
// 定时器会在wait后执行,执行完毕清空time
time = null;
fn.apply(this_, args);
}, wait);
}
}
}
三、区别
简单的理解例子,假如现有一个永不终止的高频事件
对于防抖,它会不断设置新的定时器,也就是我们一直在疯狂触发,但是永远都得不到这个触发的反馈结果
对于节流,同样的前提和操作之下,我们隔一段时间会得到一次反馈结果。