洛阳火之焰 發表於 2022-12-18 09:58:00

JavaScript中的防抖与节流-图文版

<p><img src="https://img2023.cnblogs.com/blog/151257/202212/151257-20221216144014972-1264642894.png" alt="image.png" loading="lazy"></p>
<h1 id="01防抖还是节流">01、防抖还是节流</h1>
<p><strong>防抖</strong> 与 <strong>节流</strong> 目的都是避免一定时间内,大量重复的操作造成的性能损耗。因此原理也类似,都是阻止过多的事件执行,只保留一部分来执行。适用场景略有不同,也有交叉,动手练习一遍就懂了。</p>
<table>
<thead>
<tr>
<th><strong>区别</strong></th>
<th><strong>防抖(Debounce)</strong></th>
<th><strong>节流(throttle)</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>描述</strong></td>
<td>一定延迟时间内,连续事件只执行最后一次</td>
<td>一段固定时间内只执行一次</td>
</tr>
<tr>
<td><strong>原理</strong></td>
<td>只保留一个延时<code>setTimeout()</code>的执行器,后续新的替代旧的</td>
<td>判断时间间隔,在固定间隔时间内,只执行一次。</td>
</tr>
<tr>
<td><strong>执行次数</strong></td>
<td>只执行最后一次</td>
<td>执行首次、最后一次,或首次+最后一次</td>
</tr>
<tr>
<td><strong>合适场景</strong></td>
<td>连续操作只需要一次的,如变更内容提交到后端</td>
<td>连续操作定期执行的场景:连续的UI交互,如拖拽、滚动</td>
</tr>
</tbody>
</table>
<hr>
<h1 id="02什么是防抖debounce">02、什么是防抖(Debounce)?</h1>
<p>按字面意思理解就是 <strong>防止抖动</strong>(Debounce /di'bauns/ 防抖动),本来只需要点击一次,结果手抖操作了很多次,重复执行就造成了额外的浪费。</p>
<p><img src="https://img2023.cnblogs.com/blog/151257/202212/151257-20221216144015009-702862692.png" alt="image.png" loading="lazy"></p>
<p><strong>🔸防抖函数的原理</strong>:在一定延迟时间内,连续触发的事件合并只执行 <strong>最后</strong> 一次。技术原理是用闭包保存一个延时执行函数<code>setTimeout(func, delayTime)</code>返回变量,只要延迟时间<code>delayTime</code>内新触发的执行器,就会代替旧执行器。</p>
<p><img src="https://img2023.cnblogs.com/blog/151257/202212/151257-20221216144201537-279793375.png" alt="image" loading="lazy"></p>
<p><strong>🪧实现代码</strong>:</p>
<pre><code class="language-javascript">/******************************   防抖函数******************************/
//参数func:需要防抖的函数
//参数delayTime:延时时长,单位ms
function debounce(func, delayTime) {
    //用闭包路缓存延时器id
    let timer;
    return function (...args) {
      if (timer)
            clearTimeout(timer);//清除-替换,把前浪拍死在沙滩上
      timer = setTimeout(() =&gt; {
            func.apply(this, args);
      }, delayTime);
    }
}
</code></pre>
<p><strong>🟢适用场景</strong>:</p>
<ul>
<li>✅ 提交按钮,避免重复点击提交数据,只执行最后一次。</li>
<li>✅ 文本框输入的响应:如基于输入文本服务端联想查询,对输入内容的服务端验证等,防抖就可以避免没必要的请求,节约资源。</li>
<li>✅ 连续触发的事件,如窗口的<code>resize</code>事件、窗口的滚动<code>scroll</code>事件,只处理最后一次。</li>
</ul>
<p><strong>🪧使用案例</strong>:滚动浏览器滚动条到末尾。</p>
<ul>
<li>如果不用防抖函数,<code>scroll</code>事件频繁触发,共触发了29次。</li>
<li>加上防抖函数,同样的速度移动,只触发了最后一次。</li>
</ul>
<pre><code class="language-javascript">//移动浏览器滚动条到末尾,无防抖
window.addEventListener('scroll', print); //执行了29次
//加上防抖,延迟300ms
window.addEventListener('scroll', debounce(print, 300)); //执行了1次
let index = 0;
function print() {
    console.log(index++);
}
</code></pre>
<hr>
<h1 id="03为何要节流throttle">03、为何要节流(throttle)?</h1>
<p><strong>节流</strong>(throttle)字面意思就是节约流量(throttle /ˈθrɑːtl/ 节流阀),一个小朋友一分钟只能吃一勺饭,每分钟喂了30勺,喂得太快要么食物浪费了,要么被噎到。</p>
<p><strong>🔸节流函数的原理</strong>:一定时间内只执行一次事件,在一段时间<code>intervalTime</code>内,不管触发了多少次事件(大于1)都只执行一次。</p>
<ul>
<li>因此首先需要判断间隔时间,是否在间隔时间内。</li>
<li>具体执行的时机,可选择首次,也可以选择最后一次,或者首次+最后一次。</li>
</ul>
<p><img src="https://img2023.cnblogs.com/blog/151257/202212/151257-20221216144525495-1636327442.png" alt="image" loading="lazy"></p>
<p><strong>🪧实现代码</strong>:三种实现方式</p>
<ul>
<li>实现1:单位时间内执行第一次(立即执行),节流后面的,基于时间间隔判断。</li>
<li>实现2:单位时间内执行第一次(延迟执行),节流后面的,基于延时函数<code>setTimeout()</code>。</li>
<li>实现3:执行首次+最后一次,节流中间的,比较综合全面的的实现方式!</li>
</ul>
<pre><code class="language-javascript">// 实现1:单位时间内执行第一次(立即执行),节流后面的
function throttle(func, intervalTime = 100) {
    let lastTime = 0;
    return (...args) =&gt; {
      let now = Date.now();
      //首次调用会执行
      if (now - intervalTime &gt; lastTime) {
            func.apply(this, args);
            lastTime = now;
      }
    }
}
// 实现2:单位时间内执行第一次(延迟执行),节流后面的
const throttle2 = (func, intervalTime = 100) =&gt; {
    // 定义falg,初试为true
    let flag = true;
    // 返回的函数是每次用户实际调用的节流函数
    return (...args) =&gt; {
      const ctx = this;
      // 如果flag为true,则执行定时器
      if (flag) {
            setTimeout(() =&gt; {
                func.apply(ctx, args);
                // 函数执行完毕后=true;
                flag = true;
            }, intervalTime);
      }
      //没执行完成前都为false
      flag = false;
    };
}
// 实现3:执行首次+最后一次,节流中间的,比较综合的节流方式!
function throttleMiddle(func, intervalTime = 100) {
    let timer = null;
    let startTime = 0;
    return (...args) =&gt; {
      const ctx = this;
      const now = Date.now();
      if (startTime &amp;&amp; now &lt; startTime + intervalTime) {
            //替换前面的
            clearTimeout(timer);
            timer = setTimeout(() =&gt; {
                startTime = now;
                func.apply(ctx, args);
            }, Math.max(intervalTime - (Date.now() - startTime), 0)); //剩余等候时间
      } else { //每轮首次会执行,立即执行
            startTime = now;
            func.apply(ctx, args);
      }
    }
}
// 节流-函数扩展,使用的throttleMiddle版本
Function.prototype.throttle = function (intervalTime = 100) {
    let func = this;
    let startTime, timer = null;
    //这里不能用箭头函数,会导致this污染
    return function (...args) {
      const ctx = this;
      let now = Date.now();
      if (startTime &amp;&amp; now &lt; startTime + intervalTime) {
            clearTimeout(timer);
            timer = setTimeout(() =&gt; {
                func.apply(this, args);
                startTime = now;
            }, Math.max(intervalTime - (now - startTime), 0));
      }
      else {
            startTime = now;
            func.apply(ctx, args);
      }
    }
}
</code></pre>
<p><strong>🟢适用场景</strong>:</p>
<ul>
<li>✅ 定时秒杀、抽奖按钮,运行多次提交,避免太过频繁的提交把服务端搞崩了。</li>
<li>✅ 连续的UI交互,如DOM拖拽,在窗口的resize事件、窗口的滚动scroll事件中更新UI,如果用防抖会有卡顿的现象,更适合用节流。</li>
</ul>
<p><strong>🪧使用案例</strong>:滚动浏览器滚动条到末尾。</p>
<ul>
<li>如果不用防抖函数,<code>scroll</code>事件频繁触发,共触发了29次。</li>
<li>加上节流函数,同样的速度移动,执行了4次,间隔均匀。</li>
</ul>
<pre><code class="language-javascript">//移动浏览器滚动条到末尾
window.addEventListener('scroll', print); //执行了29次
//加上节流,延迟300ms
window.addEventListener('scroll', throttle(print, 300)); //执行了4次
let index = 0;
function print() {
    console.log(index++);
}
</code></pre>
<hr>
<blockquote>
<p><strong>©️版权申明</strong>:版权所有@安木夕,本文内容仅供学习,欢迎指正、交流,转载请注明出处!<em>原文编辑地址-语雀</em></p>
</blockquote><br><br>
来源:https://www.cnblogs.com/anding/p/16987336.html
頁: [1]
查看完整版本: JavaScript中的防抖与节流-图文版