写点什么

带你掌握 JS 防抖与节流

发布于: 20 小时前

​​​​​​摘要:防抖与节流可谓是面试常见,其实很好理解,下面带你分分钟了解防抖与节流的基本思想与写法~


本文分享自华为云社区《JS防抖与节流快速了解与应用》,作者:北极光之夜。  。

一.速识防抖


防抖与节流可谓是面试常见,其实很好理解,下面带你分分钟了解防抖与节流的基本思想与写法~


在这之前,比如我们先定义一个按钮,并绑定一个点击事件,执行要触发的事件:


<!-- 定义一个按钮 --><input type="button" id="btn" value="按钮" />
<script>// 获取标签 var btn = document.getElementById("btn");// 绑定事件 btn.addEventListener("click", real);// 要触发的事件 function real(e) { console.log("北极光之夜。"); console.log(e); }</script>
复制代码


执行如下:



可以发现,一直点击会一直触发事件,如果这个事件为发送一个请求,那么这对与服务器来说是很不友好的。同样的请求因为用户的多次点击而多次发送请求,返回的结果和只点击一次是一样的,大大加重服务器压力和影响性能。所以,我们引入防抖的概念,简单来说,防抖就是通过 setTimeout 的方式,在一定的时间间隔内,将多次触发变成一次触发。 直接看下面例子:


1.通过 setTimeout 的方式延迟执行

  

第一种方式为通过设置 setTimeout 定时器的方式延迟执行,当快速多次点击的时候,每一次都会重置定时器,只有你一段时间都不点击时定时器才能到达条件并执行事件函数。


<input type="button" id="btn" value="按钮" />    <script>      var btn = document.getElementById("btn");      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间      btn.addEventListener("click", trigger(real, 1000));      function trigger(fn, delay) {        // 设置time为定时器,初始为 null        var time = null;         // 闭包原理,返回一个函数        return function () {          // 如果定时器存在清空定时器          if (time) {            clearTimeout(time);          }          // 设置定时器,规定时间后执行真实要执行的函数          time = setTimeout(() => {          // 将参数传递给真实执行的函数,因为箭头函数继承父级作用域,所以直接...arguments            fn(...arguments);          }, delay);        };      }      //真实要执行函数      function real(e) {        console.log("北极光之夜。");        console.log(e);      }       </script>  
复制代码


其中会利用闭包的原理形成作用域,使得定时器不会被下一次点击重复或清空。闭包不清楚的可以看我这篇文章👉:https://auroras.blog.csdn.net/article/details/119520871


运行结果如下,每次点击都延迟执行。狂点时只有停下后才会执行:



2.通过 setTimeout 的方式第一次会执行,后面不执行: 

  

可以发现,第一种方式虽然延迟执行了,但是当用户第一次点的时候也要延迟执行,那就很不友好了。所以下面改进,使得第一次点的时候立即执行,狂点的时候只有第一次有效后面的都没效:


 <input type="button" id="btn" value="按钮" />    <script>      var btn = document.getElementById("btn");      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间      btn.addEventListener("click", trigger(real, 1000));     function trigger(fn, delay) {       // 设置time为定时器,初始为 null        var time = null;        return function () {         //定义一个firstClick,判断是否第一次执行,初始值为true          var firstClick = !time;         //第一次会立即执行          if (firstClick) {            fn(...arguments);          }           // 如果定时器存在清空定时器          if (time) {            clearTimeout(time);          }           // 设置定时器,此时firstClick会变为false,规定时间后time才会为null          time = setTimeout(() => {            time = null;          }, delay);        };      }       //真实要执行函数      function real(e) {        console.log("北极光之夜。");        console.log(e);      }       </script>  
复制代码


运行结果如下,第一次点的时候立即执行,狂点的时候只有第一次有效后面的都没效:



3.通过 setTimeout 的方式第一次会执行和最后一次执行


前两个其实就是防抖的经典例子了。这里是扩展知识,继续改进上面案例使得只点击一次的时候立即执行。当点击多次时第一次和最后一次执行。


<input type="button" id="btn" value="按钮" />    <script>      var btn = document.getElementById("btn");      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间      btn.addEventListener("click", trigger(real, 1000));     function trigger(fn, delay) {       // 设置time为定时器,初始为 null        var time = null;        return function () {         //定义一个firstClick,判断是否第一次执行,初始值为true          var firstClick = !time;         //第一次会立即执行          if (firstClick) {            fn(...arguments);          }           // 如果定时器存在清空定时器          if (time) {            clearTimeout(time);          }           // 设置定时器,此时firstClick会变为false,规定时间后time才会为null          time = setTimeout(() => {            time = null;            // 如果firstClick为true,执行             if (!firstClick) {              fn(...arguments);            }          }, delay);        };      }       //真实要执行函数      function real(e) {        console.log("北极光之夜。");        console.log(e);      }       </script>  
复制代码


运行结果如下,只点击一次的时候立即执行。当点击多次时第一次和最后一次执行:



二.速识节流

  

节流其实就很好理解了,减少一段时间的触发频率。简单来说,就是你一直狂点不停的话,它会每隔一定时间就执行一次。它与防抖最大的区别就是,无论事件触发多么频繁,都可以保证在规定时间内可以执行一次执行函数。下面利用计算时间戳实现:


 <input type="button" id="btn" value="按钮" />    <script>      var btn = document.getElementById("btn");      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为限制时间      btn.addEventListener("click", trigger(real, 500));     function trigger(fn, delay) {       // 设置bef,为上一次执行时间,初始为0        var bef = 0;        return function () {        // 获取当前时间戳          var now = new Date().getTime();          //如果当前时间减去上次时间大于限制时间时才执行          if (now - bef > delay) {           // 执行函数            fn(...arguments);            //执行后,上次时间赋值为这次执行时间            bef = now;          }        };      }      //真实要执行函数      function real(e) {        console.log("北极光之夜。");        console.log(e);      }       </script>  
复制代码


运行结果如下,一点就运行。狂点不停的话,每隔 500 毫秒才执行一次:



也可以用定时器实现节流,如下

实现第一次点的时候也延迟执行,狂点不停的话,它会每隔一定时间就执行一次。


 <input type="button" id="btn" value="按钮" />    <script>      var btn = document.getElementById("btn");      btn.addEventListener("click", trigger(real, 500));      function real(e) {        console.log("北极光之夜。");        console.log(e);      }      function trigger(fn, delay) {      // flag为ture        var flag = true;        return function () {         // 如果flag为true执行定时器          if (flag) {            setTimeout(() => {              //到规定时间后执行函数,同时 flag = true;              fn(...arguments);              flag = true;            }, delay);          }          // flag = false;防止一直执行          flag = false;        };      }</script>
复制代码


效果如下:



三.总结


防抖与节流方法多多,不同的需求也会有不同的写法,重要的是搞清原理就好。防抖就是通过 setTimeout 的方式,在一定的时间间隔内,将多次触发变成一次触发 。节流:就是减少一段时间的触发频率。防抖与节流最大的区别就是,无论事件触发多么频繁,都可以保证在规定时间内可以执行一次执行函数。


点击关注,第一时间了解华为云新鲜技术~

发布于: 20 小时前阅读数: 7
用户头像

提供全面深入的云计算技术干货 2020.07.14 加入

华为云开发者社区,提供全面深入的云计算前景分析、丰富的技术干货、程序样例,分享华为云前沿资讯动态,方便开发者快速成长与发展,欢迎提问、互动,多方位了解云计算! 传送门:https://bbs.huaweicloud.com/

评论

发布
暂无评论
带你掌握JS防抖与节流