Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

如何在 React 中使用 Throttle 和 Debounce 来提高性能

Posted on 2022-05-30

概述

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

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Lou Plummer
  • Luke Wroblewski
  • Matt Stoller
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme