您的位置:首页 > Web前端

闲聊前端性能----防抖、节流、重绘与回流。

2020-02-04 04:13 495 查看

        在最近,小米9卖的特别火,在官方抢购的时候基本都是一点既空。这不禁让我想到了,官网是怎样控制顾客不停点击发起请求而不导致官网崩溃的呢?这由此引出了前端性能优化中的----防抖和节流。在闲聊完后你就会发现有些时候在抢购商品的时候,你用鼠标在几秒钟不停的按了数十次,或许它仅仅是发送了你第一次点击抢购的那个请求。所以说 抢购时间内的第一次点击尤为关键!

 

       下面来介绍一下什么是防抖!

       防抖:任务频繁触发的情况下,只有任务触发的间隔超过制定的时间间隔的时候,任务才会被执行。

下面引用一下知乎上的一个例子:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>防抖</title>
</head>
<body>
<button id="debounce">点我防抖!</button>

<script>
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("防抖成功!");
}

</script>
</body>
</html>

       这是知乎上的一个例子,创建一个定时器,如果在规定时间内重复触发该事件,就会调用clearTimeout清除掉上一个定时器,重置定时器。也就是说,这件事本来就是需要等待的,并非立即执行的,如果用户反复点击,那只好重新等待了。所以,

fn.call(this, arguments)
 其实是将不确定变量替换到函数中了。在这之前已经聊过了arguments,可以看下我之前写得 闲聊js中的apply、call和arguments

       

       在上面的这个例子中是非立即执行版。当然,我把知乎的例子修改一下它,将它变成立即执行版。

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>防抖</title>
</head>
<body>
<button id="debounce">点我防抖!</button>

<script>
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("防抖成功!");
}

</script>
</body>
</html>

其原理和立即执行版本一样,只是点击执行的先后顺序不同。

 

 

下面 我们来聊一下什么是节流吧!

    节流:指定时间间隔内只会执行一次任务。

这有点像我们刷抢购一样,当我们在某段时间间隔内触发了多次事件,其实,它只执行一次请求!

下面 我们再来引用知乎的一个例子就会明白了!

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>节流</title>
</head>
<body>

<button id="throttle">点我节流!</button>

<script>
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("节流成功!");
}

</script>
</body>
</html>

从这个例子可以看出,节流可以防止在某时间间隔内重复发送请求!其和防抖有点相似,但其有本质的区别,虽然都是防止重复触发事件!

防抖是需要等待多久时间才能再触发一次事件!

节流是多久时间内只能触发一次事件!

 

重绘与回流

在介绍重绘和回流之前,最好先了解一下浏览器是如何解析解析URL的,或者看一下《浏览器渲染页面过程剖析》

好!现在我们进入正题 !什么是重绘和回流!

 

重绘(repaint):当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要 UI 层面的重新像素绘制,因此损耗较少。

回流(reflow):又叫重排(layout)。当元素的尺寸、结构或者触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。

 

或许这概念比较抽象,讲起来很难理解!简单点说,就比如我们页面中的某些颜色会发生动态改变,而木有影响到尺寸,布局、位置、结构这些改变的,就叫做重绘,而例如动态添加结点、改变尺寸、位置这些的,就叫做回流!

回流的损耗是比较大的!所以尽量不要产生太多的回流!就比如,样式的动态修改不要多步而尽量应一步到位!

为了避免大量的重绘和回流!

  1. 避免频繁操作样式,可汇总后统一一次修改
  2. 尽量使用 class 进行样式修改,而不是直接操作样式
  3. 减少 DOM 的操作,可使用字符串一次性插入

 

回流必定会触发重绘,重绘不一定会触发回流。重绘的开销较小,回流的代价较高。

转载于:https://www.cnblogs.com/binguo666/p/10535948.html

  • 点赞
  • 收藏
  • 分享
  • 文章举报
diaoyi1932 发布了0 篇原创文章 · 获赞 0 · 访问量 140 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: