前端进阶版本 ,性能优化----防抖、节流、重绘与回流。

Ummi ·
更新时间:2024-11-14
· 509 次阅读

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

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

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

防抖 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 的操作,可使用字符串一次性插入

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


作者:搬砖-搬搬搬



性能 重绘 版本 性能优化 优化 前端

需要 登录 后方可回复, 如果你还没有账号请 注册新账号