概述
Throttle
和Debounce
解决优化问题。
Throttle
– 以特定频率跳过函数调用。
Debounce
– 延迟函数调用,直到自上次调用以来经过一定时间。
节流和去抖动方案:
使用油门的例子:
1)如果用户调整了浏览器窗口的大小,我们需要改变网站的内容。
如果没有优化,会发生以下情况。在每个窗口调整大小事件上,都会调用窗口调整大小事件处理程序。因此,例如,如果用户在 10 秒内调整窗口大小,则可能会发生 100、200 等我们需要处理的事件。
Throttle
允许我们设置一个时间间隔,比该时间间隔更频繁地不会调用事件处理程序。如果我们使用Throttle
指定 1 秒的间隔,那么窗口调整大小事件处理程序的执行次数将为 10。
2) 向用户显示页面滚动的百分比。当用户滚动页面时,会发生scroll
事件,我们需要处理这些事件。使用throttle
,我们可以通过设置时间间隔来减少处理的滚动事件的数量。
使用油门的例子:
1)处理用户的搜索查询数据。
当用户输入搜索查询时,会为他们提供搜索选项。它以下列方式发生。
当更改用户输入的文本时,将向服务器发送一个请求,我们将在其中传输已打印的字符。然后我们从服务器获得可能的搜索查询选项的响应并将它们显示给用户。
每次用户更改文本时,都会调用一个事件处理程序,其中向服务器发送一个请求。
为了优化发送到服务器的请求数量,我们使用Debounce
。
当用户更改文本时,使用Debounce
允许我们创建一个计时器,例如 1 秒。如果 1 秒过去并且用户没有再次更改文本,则调用事件处理程序并将请求发送到服务器。如果用户在 1 秒内第二次更改文本,则重置第一个计时器并在 1 秒内再次创建一个新计时器。
因此,如果用户快速编辑搜索文本(不到 1 秒),那么在用户停止输入后,请求将只发送到服务器一次。
2) 将分析数据发送到服务器。例如,用户在站点周围移动鼠标,我们将鼠标坐标写入一个数组,之后Debounce
允许我们仅在客户端停止移动鼠标后才向服务器发送有关客户端鼠标移动的信息。
因此,在本文中,我将向您展示如何在 React 应用程序中使用Throttle
和Debounce
。
第 1 步 – 应用程序模板
使用create-react-app
创建应用模板并运行它:
npx create-react-app throttle-debounce cd throttle-debounce npm start
我们用我们的样式替换App.css
文件的内容:
body { display : flex ; justify-content : center ; width : 100% ; } h1 { text-align : center ; margin : 0.5rem 0 ; } .l-scroll { overflow-y : scroll ; overflow-x : hidden ; width : 380px ; height : 200px ; margin-top : 0.5rem ; } .scroll-content { width : 100% ; background-color : bisque ; padding : 0 1rem ; } .l-scroll ::-webkit-scrollbar { width : 10px ; height : 8px ; background-color : darkturquoise ; } .l-scroll ::-webkit-scrollbar-thumb { background-color : blueviolet ; }
让我们用我们的应用模板替换App.js
文件的内容:
import ' ./App.css ' ; import { useMemo } from ' react ' ; function App () { return ( <> < h1 > Throttle & Debounce </ h1 > < div className = "l-scroll" > < div className = "scroll-content" > < TallContent /> </ div > </ div > </> ); } // High height scrollable content function TallContent (){ const dataElements = useMemo (() => { const genData = []; for ( let i = 1 ; i <= 200 ; i ++ ){ genData . push ( < div key = { i } > Line: { i } </ div > ); } return genData ; }, []); return ( <> { dataElements } </> ); } export default App ;
应用程序模板已经准备好,让我们继续第二步——通常的滚动事件处理程序。
第 2 步 – 常规事件处理程序
在这里,我们将为scroll
事件添加一个常用的事件处理程序,并计算用户滚动页面元素时对该处理程序的调用次数。
让我们将事件处理程序调用次数的状态添加到App
组件:
// At the beginning of the file import { useState , useMemo } from ' react ' ; // Inside the App component const [ scrollHandleCount , setScrollHandleCount ] = useState ( 0 );
然后我们添加一个滚动事件处理程序,为此我们将onScroll
属性添加到h1
标题下的元素:
// Before < div className = "l-scroll" > ... </ div > // After < div className = "l-scroll" onScroll = { handleScroll } > ... </ div >
我们还将为App
组件添加一个处理handleScroll
事件的函数:
function handleScroll (){ handleUsualScroll (); }
在handleScroll
函数中,我们放置了一个函数来处理通常的事件。让我们将此函数添加到我们的App
组件中:
function handleUsualScroll (){ setScrollHandleCount (( prevState ) => { return ++ prevState ; }); }
它只是向用户显示计数器的状态,为此我们在h1
标题下添加一行代码:
< span > Usual scroll handle count: { scrollHandleCount } </ span > < br />
现在,当滚动页面上的元素时,我们应该看到对handleUsualScroll()
函数的调用次数。
目前App
组件的完整代码:
function App () { const [ scrollHandleCount , setScrollHandleCount ] = useState ( 0 ); return ( <> < h1 > Throttle & Debounce </ h1 > < span > Usual scroll handle count: { scrollHandleCount } </ span > < br /> < div className = "l-scroll" onScroll = { handleScroll } > < div className = "scroll-content" > < TallContent /> </ div > </ div > </> ); function handleScroll (){ handleUsualScroll (); } function handleUsualScroll (){ setScrollHandleCount (( prevState ) => { return ++ prevState ; }); } }
第 3 步 – 带 Throttle 的事件处理程序
在我们的例子中, Throttle
事件处理程序应该导致scrollThrottleHandleCount
计数器增加,同时跳过调用以在特定时间间隔增加计数器。
为了实施我们的计划,我们需要一个计时器,在该计时器开始时Throlle
状态进入In progress
。在这种情况下,如果状态为In Progerss
,则跳过用户事件的处理(滚动页面元素)。
一旦计时器触发, Throttle
状态就会更改为Not in progress
,这意味着我们的处理程序将再次处理用户事件。因此,以指定的时间间隔跳过用户事件。
我们实现上述:
// Add useRef to store inProgress state import { useState , useRef , useMemo } from ' react ' ;
接下来,在App
组件中,使用Throttle
和ref
添加事件处理程序调用计数器的状态以存储inProgress
状态:
// Number of event handler calls with Throttle const [ scrollThrottleHandleCount , setScrollThrottleHandleCount ] = useState ( 0 ); // Keeping the state in progress const throttleInProgress = useRef ();
这里需要注意的是, throttleInProgress
是与计时器相关的副作用的一部分,这意味着我们会将状态存储在ref
对象中,因为useRef
返回的对象存在于组件的整个生命周期中,而在与useRef
,在更改useState
返回的对象的current
属性时,没有额外的渲染组件。
现在让我们将带有Throttle
的事件处理程序本身添加到App
组件中:
function handleThrottleScroll (){ // If the state is inProgress - exit the function, // skip event processing if ( throttleInProgress . current ){ return ; } // Set inProgress to true and start the timer throttleInProgress . current = true ; setTimeout (() => { // Increment the throttleHandleCount // state by one setScrollThrottleHandleCount (( prevState ) => { return ++ prevState ; }); // Set inProgress to false, which means // that setTimeout will work // again on the next run throttleInProgress . current = false ; }, 500 ); }
剩下两个简单的步骤:使用Throttle
向用户添加计数器状态的显示,并将 handleThrottleScroll( handleThrottleScroll()
添加到handleScroll()
:
// After heading h1 < span > Throttle scroll handle count: { scrollThrottleHandleCount } </ span > // In the handleScroll() function after handleUsualScroll(); handleThrottleScroll ();
普通事件处理程序调用应用程序的业务逻辑 181 次,而Throttle
只有 9 次。
带有Throttle
的App
组件的完整代码:
function App () { const [ scrollHandleCount , setScrollHandleCount ] = useState ( 0 ); const [ scrollThrottleHandleCount , setScrollThrottleHandleCount ] = useState ( 0 ); const throttleInProgress = useRef (); return ( <> < h1 > Throttle & Debounce </ h1 > < span > Usual scroll handle count: { scrollHandleCount } </ span > < br /> < span > Throttle scroll handle count: { scrollThrottleHandleCount } </ span > < br /> < div className = "l-scroll" onScroll = { handleScroll } > < div className = "scroll-content" > < TallContent /> </ div > </ div > </> ); function handleScroll (){ handleUsualScroll (); handleThrottleScroll (); } function handleUsualScroll (){ setScrollHandleCount (( prevState ) => { return ++ prevState ; }); } function handleThrottleScroll (){ if ( throttleInProgress . current ){ return ; } throttleInProgress . current = true ; setTimeout (() => { setScrollThrottleHandleCount (( prevState ) => { return ++ prevState ; }); throttleInProgress . current = false ; }, 500 ); } }
让我们继续进行最后一步 – 实现Debounce
事件处理程序。
第 4 步 — 带去抖动的事件处理程序
在我们的示例中, Debounce
延迟了scrollDebounceHandleCount
计数器的递增,直到自最后一次调用事件处理程序***过去了一定的时间。
让我们用Debounce
将调用次数的状态添加到事件处理程序中,以将ref
ID 存储在App
组件中:
const [ scrollDebounceHandleCount , setScrollDebounceHandleCount ] = useState ( 0 ); const timerDebounceRef = useRef ();
然后我们向用户显示scrollDebounceHandleCount
的数量并将我们的handleDebounceScroll()
方法添加到handleScroll()
:
// After h1 < span > Debound scroll handle count: { scrollDebounceHandleCount } </ span > // In handleScroll() function handleDebounceScroll ();
剩下的就是写handleDebounceScroll
函数:
function handleDebounceScroll (){ // If the timer ID is set, reset the timer if ( timerDebounceRef . current ){ clearTimeout ( timerDebounceRef . current ); } // We start the timer, the returned timer ID // is written to timerDebounceRef timerDebounceRef . current = setTimeout (() => { // Increasing the counter for the number of // executions of the business logic // of the application with Debounce setScrollDebounceHandleCount (( prevState ) => { return ++ prevState ; }); }, 500 ); }
因此,仅当用户停止滚动页面元素超过或等于 500 毫秒时, Debounce
计数器才会增加:
App
组件全文:
function App () { const [ scrollHandleCount , setScrollHandleCount ] = useState ( 0 ); const [ scrollThrottleHandleCount , setScrollThrottleHandleCount ] = useState ( 0 ); const [ scrollDebounceHandleCount , setScrollDebounceHandleCount ] = useState ( 0 ); const throttleInProgress = useRef (); const timerDebounceRef = useRef (); return ( <> < h1 > Throttle & Debounce </ h1 > < span > Usual scroll handle count: { scrollHandleCount } </ span > < br /> < span > Throttle scroll handle count: { scrollThrottleHandleCount } </ span > < br /> < span > Debound scroll handle count: { scrollDebounceHandleCount } </ span > < div className = "l-scroll" onScroll = { handleScroll } > < div className = "scroll-content" > < TallContent /> </ div > </ div > </> ); function handleScroll (){ handleUsualScroll (); handleThrottleScroll (); handleDebounceScroll (); } function handleUsualScroll (){ setScrollHandleCount (( prevState ) => { return ++ prevState ; }); } function handleThrottleScroll (){ if ( throttleInProgress . current ){ return ; } throttleInProgress . current = true ; setTimeout (() => { setScrollThrottleHandleCount (( prevState ) => { return ++ prevState ; }); throttleInProgress . current = false ; }, 500 ); } function handleDebounceScroll (){ if ( timerDebounceRef . current ){ clearTimeout ( timerDebounceRef . current ); } timerDebounceRef . current = setTimeout (() => { setScrollDebounceHandleCount (( prevState ) => { return ++ prevState ; }); }, 500 ); } }
订阅博客,点赞,添加到书签。
不要忘记独角兽。
感谢您的关注!
原文: https://dev.to/andreyen/how-to-use-throttle-and-debounce-in-react-app-13af