重绘指的是浏览器根据 CSS 样式计算并绘制出页面中的元素。
当元素的位置、大小或者颜色等属性发生变化时,浏览器只需要重新绘制这个元素即可,这个过程称为重绘。
重绘比重排消耗的资源要少,因此在性能优化时需要尽可能避免重排。
每当 DOM 结构或者样式发生变化时,浏览器都需要重新计算布局和绘制元素,这个过程称为重排。
节流指的是在一定时间间隔内只执行一次特定的操作
节流的操作:在某个时间内(比如500ms),某个函数只能被触发一次;
限制点击事件的触发频率或者滚动事件的处理次数。这种技术可以避免某些高频率事件的过度触发,从而减轻 JavaScript 引擎的负担,并提升用户体验。通常可以使用定时器或者时间戳等方式实现节流。
例如:
当用户连续多次点击按钮时,只有一次点击会被响应:
function throttle(fn, delay) {
let timer = null;
return function() {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arguments);
timer = null;
}, delay);
}
}
}
const button = document.querySelector('button');
button.addEventListener('click', throttle(() => {
console.log('clicked');
}, 1000));
举例子 :
在飞机大战的游戏中,我们按下空格会发射一个子弹:
很多飞机大战的游戏中会有这样的设定,即使按下的频率非常快,子弹也会保持一定的频率来发射;(其实很多的街机游戏都是这样的,普通攻击有一个最高的频率);
比如1秒钟只能发射一次,即使用户在这1秒钟按下了10次,子弹会保持发射一颗的频率来发射;
但是事件是触发了10次的,响应的函数只触发了一次;
监听页面的滚动事件;
鼠标移动事件;
用户频繁点击按钮操作;
游戏中的一些设计;
总之,依然是密集的事件触发,但是这次密集事件触发的过程,不会等待最后一次才进行函数调用,而是会按照一定的频率进行调用。
通过防抖和节流来限制事件频繁的发生
防抖的操作:只有在某个时间内,没有再次触发某个函数时,才真正的调用这个函数;
- 当事件触发时,相应的函数并不会立即触发,而是会等待一定的时间;
- 当事件密集触发时,函数的触发会被频繁的推迟;
- 只有等待了一段时间也没有事件触发,才会真正的执行响应函数;
输入框中频繁的输入内容,搜索或者提交信息;
频繁的点击按钮,触发某个事件;
监听浏览器滚动事件,完成某些特定操作;
用户缩放浏览器的resize事件;
总之,密集的事件触发,我们只希望触发比较靠后发生的事件,就可以使用防抖函数;
防抖函数可以在一段时间内忽略重复的函数调用,只执行最后一次调用。这个时间段称为防抖时间。如果在防抖时间内再次调用该函数,则会重新计时,直到防抖时间结束才会执行该函数。
以下是一个简单的防抖函数实现:
javascriptCopy Codefunction debounce(func, delay) {
let timer = null;
return function() {
const context = this;
const args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
func.apply(context, args);
}, delay);
}
}
上述代码中,`debounce` 函数接收两个参数:要执行的函数 `func` 和防抖时间 `delay`。它返回一个新的函数,该函数会在调用时启动定时器,并在防抖时间结束后执行 `func` 函数。
使用该函数可以对某个函数进行防抖处理:
javascriptCopy Codefunction handleInput() {
console.log('input changed');
}
const debouncedHandleInput = debounce(handleInput, 1000);
document.querySelector('input').addEventListener('input', debouncedHandleInput);
上述代码中,`handleInput` 函数会在输入框内容改变时被调用。使用 `debounce` 函数对其进行防抖处理后,只有在输入框内容改变后 1 秒钟内没有再次改变时,才会执行 `handleInput` 函数。
节流函数可以限制函数被触发的频率,例如每隔一定时间才能触发一次。这个时间段称为节流时间。
以下是一个简单的节流函数实现:
javascriptCopy Codefunction throttle(func, delay) {
let lastTime = 0;
return function() {
const context = this;
const args = arguments;
const now = Date.now();
if (now - lastTime >= delay) {
func.apply(context, args);
lastTime = now;
}
}
}
上述代码中,`throttle` 函数接收两个参数:要执行的函数 `func` 和节流时间 `delay`。它返回一个新的函数,该函数会在调用时判断当前时间与上一次调用时间的差值是否大于等于节流时间,如果是则执行 `func` 函数,并更新上一次调用时间。
使用该函数可以对某个函数进行节流处理:
javascriptCopy Codefunction handleScroll() {
console.log('scrolling');
}
const throttledHandleScroll = throttle(handleScroll, 1000);
window.addEventListener('scroll', throttledHandleScroll);
上述代码中,`handleScroll` 函数会在滚动页面时被调用。使用 `throttle` 函数对其进行节流处理后,每隔 1 秒钟才会触发一次 `handleScroll` 函数。
要清除定时器,可以使用 `clearTimeout` 和 `clearInterval` 这两个 JavaScript 方法。
- `clearTimeout` 用于清除通过 `setTimeout` 创建的定时器。
- `clearInterval` 用于清除通过 `setInterval` 创建的定时器。
这两个方法都接收一个参数,即要清除的定时器的标识符。该标识符是在创建定时器时返回的。
javascriptCopy Code// 使用 setTimeout 创建定时器
const timeoutId = setTimeout(function() {
console.log('定时器执行了');
}, 2000);
// 清除定时器
clearTimeout(timeoutId);
上述代码中,首先使用 `setTimeout` 创建了一个定时器,并将其标识符存储在 `timeoutId` 变量中。然后,通过调用 `clearTimeout` 方法并传入 `timeoutId`,可以清除该定时器,使其不再执行。
同样的方式也适用于 `setInterval` 和 `clearInterval`:
javascriptCopy Code// 使用 setInterval 创建定时器
const intervalId = setInterval(function() {
console.log('定时器执行了');
}, 1000);
// 清除定时器
clearInterval(intervalId);
上述代码中,使用 `setInterval` 创建了一个定时器,并将其标识符存储在 `intervalId` 变量中。然后,通过调用 `clearInterval` 方法并传入 `intervalId`,可以清除该定时器,停止其重复执行。
需要注意的是,在清除定时器之前,必须先保存定时器的标识符。否则,无法找到要清除的定时器。