下面来介绍一下什么是防抖!
防抖:任务频繁触发的情况下,只有任务触发的间隔超过制定的时间间隔的时候,任务才会被执行。
下面引用一下知乎上的一个例子:
防抖
window.onload = function() {
// 1、获取这个按钮,并绑定事件
var myDebounce = document.getElementById("debounce");
myDebounce.addEventListener("click", debounce(sayDebounce));
}
// 2、防抖功能函数,接受传参
function debounce(fn) {
// 4、创建一个标记用来存放定时器的返回值
let timeout = null;
return function() {
// 5、每次当用户点击/输入的时候,把前一个定时器清除
clearTimeout(timeout);
// 6、然后创建一个新的 setTimeout,
// 这样就能保证点击按钮后的 interval 间隔内
// 如果用户还点击了的话,就不会执行 fn 函数
timeout = setTimeout(() => {
fn.call(this, arguments);
}, 1000);
};
}
// 3、需要进行防抖的事件处理
function sayDebounce() {
// ... 有些需要防抖的工作,在这里执行
console.log("防抖成功!");
}
这是知乎上的一个例子,创建一个定时器,如果在规定时间内重复触发该事件,就会调用clearTimeout清除掉上一个定时器,重置定时器。也就是说,这件事本来就是需要等待的,并非立即执行的,如果用户反复点击,那只好重新等待了。所以,fn.call(this, arguments)
其实是将不确定变量替换到函数中了。
在上面的这个例子中是非立即执行版。当然,我把知乎的例子修改一下它,将它变成立即执行版。
防抖
window.onload = function() {
// 1、获取这个按钮,并绑定事件
var myDebounce = document.getElementById("debounce");
myDebounce.addEventListener("click", debounce(sayDebounce));
}
// 2、防抖功能函数,接受传参
function debounce(fn) {
// 4、创建一个标记用来存放定时器的返回值
let timeout = null;
//5.创建一个判断是否可点击值
let doit = true;
return function() {
// 5、当doit为真,既用户重复点击时,清除定时器
if(doit)clearTimeout(timeout);
//6.当doit为false时,既用户可点击,再将doit设为true,防止用户重复点击
else{
fn();
doit = true;
}
//7.设置定时器,这样就能保证点击按钮后的 interval 间隔内
// 如果用户还点击了的话,就不会执行 将doit设为false函数
timeout = setTimeout(() => {
doit = false;
}, 1000);
};
}
// 3、需要进行防抖的事件处理
function sayDebounce() {
// ... 有些需要防抖的工作,在这里执行
console.log("防抖成功!");
}
其原理和立即执行版本一样,只是点击执行的先后顺序不同。
下面 我们来聊一下什么是节流吧!
节流:指定时间间隔内只会执行一次任务。
这有点像我们刷抢购一样,当我们在某段时间间隔内触发了多次事件,其实,它只执行一次请求!
下面 我们再来引用知乎的一个例子就会明白了!
节流
window.onload = function() {
// 1、获取按钮,绑定点击事件
var myThrottle = document.getElementById("throttle");
myThrottle.addEventListener("click", throttle(sayThrottle));
}
// 2、节流函数体
function throttle(fn) {
// 4、通过闭包保存一个标记
let canRun = true;
return function() {
// 5、在函数开头判断标志是否为 true,不为 true 则中断函数
if(!canRun) {
return;
}
// 6、将 canRun 设置为 false,防止执行之前再被执行
canRun = false;
// 7、定时器
setTimeout( () => {
fn.call(this, arguments);
// 8、执行完事件(比如调用完接口)之后,重新将这个标志设置为 true
canRun = true;
}, 1000);
};
}
// 3、需要节流的事件
function sayThrottle() {
console.log("节流成功!");
}
从这个例子可以看出,节流可以防止在某时间间隔内重复发送请求!其和防抖有点相似,但其有本质的区别,虽然都是防止重复触发事件!
防抖是需要等待多久时间才能再触发一次事件!
节流是多久时间内只能触发一次事件!
重绘与回流
在介绍重绘和回流之前,最好先了解一下浏览器是如何解析解析URL的,或者看一下《浏览器渲染页面过程剖析》
好!现在我们进入正题 !什么是重绘和回流!
重绘(repaint):当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要 UI 层面的重新像素绘制,因此损耗较少。
回流(reflow):又叫重排(layout)。当元素的尺寸、结构或者触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。
或许这概念比较抽象,讲起来很难理解!简单点说,就比如我们页面中的某些颜色会发生动态改变,而木有影响到尺寸,布局、位置、结构这些改变的,就叫做重绘,而例如动态添加结点、改变尺寸、位置这些的,就叫做回流!
回流的损耗是比较大的!所以尽量不要产生太多的回流!就比如,样式的动态修改不要多步而尽量应一步到位!
为了避免大量的重绘和回流!
避免频繁操作样式,可汇总后统一一次修改
尽量使用 class 进行样式修改,而不是直接操作样式
减少 DOM 的操作,可使用字符串一次性插入
回流必定会触发重绘,重绘不一定会触发回流。重绘的开销较小,回流的代价较高。
作者:搬砖-搬搬搬