Files
shiny/reference/debounce.html
2025-06-19 15:31:31 +00:00

209 lines
18 KiB
HTML

<!DOCTYPE html>
<!-- Generated by pkgdown: do not edit by hand --><html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Slow down a reactive expression with debounce/throttle — debounce • shiny</title><!-- jquery --><script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" integrity="sha512-v2CJ7UaYy4JwqLDIrZUI/4hqeoQieOmAZNXBeQyjo21dadnwR+8ZaIJVT8EE2iyI61OV8e6M8PP2/4hpQINQ/g==" crossorigin="anonymous" referrerpolicy="no-referrer"></script><!-- Bootstrap --><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" integrity="sha256-bZLfwXAP04zRMK2BjiO8iu9pf4FbLqX6zitd+tIvLhE=" crossorigin="anonymous"><script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js" integrity="sha256-nuL8/2cJ5NDSSwnKD8VqreErSWHtnEP9E7AySL+1ev4=" crossorigin="anonymous"></script><!-- bootstrap-toc --><link rel="stylesheet" href="../bootstrap-toc.css"><script src="../bootstrap-toc.js"></script><!-- Font Awesome icons --><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css" integrity="sha256-mmgLkCYLUQbXn0B1SRqzHar6dCnv9oZFPEC1g1cwlkk=" crossorigin="anonymous"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/v4-shims.min.css" integrity="sha256-wZjR52fzng1pJHwx4aV2AO3yyTOXrcDW7jBpJtTwVxw=" crossorigin="anonymous"><!-- clipboard.js --><script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/2.0.6/clipboard.min.js" integrity="sha256-inc5kl9MA1hkeYUt+EC3BhlIgyp/2jDIyBLS6k3UxPI=" crossorigin="anonymous"></script><!-- headroom.js --><script src="https://cdnjs.cloudflare.com/ajax/libs/headroom/0.11.0/headroom.min.js" integrity="sha256-AsUX4SJE1+yuDu5+mAVzJbuYNPHj/WroHuZ8Ir/CkE0=" crossorigin="anonymous"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/headroom/0.11.0/jQuery.headroom.min.js" integrity="sha256-ZX/yNShbjqsohH1k95liqY9Gd8uOiE1S4vZc+9KQ1K4=" crossorigin="anonymous"></script><!-- pkgdown --><link href="../pkgdown.css" rel="stylesheet"><script src="../pkgdown.js"></script><meta property="og:title" content="Slow down a reactive expression with debounce/throttle — debounce"><meta property="og:description" content="Transforms a reactive expression by preventing its invalidation signals from
being sent unnecessarily often. This lets you ignore a very &quot;chatty&quot; reactive
expression until it becomes idle, which is useful when the intermediate
values don't matter as much as the final value, and the downstream
calculations that depend on the reactive expression take a long time.
debounce and throttle use different algorithms for slowing down
invalidation signals; see Details."><meta property="og:image" content="/logo.png"><!-- mathjax --><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js" integrity="sha256-nvJJv9wWKEm88qvoQl9ekL2J+k/RWIsaSScxxlsrv8k=" crossorigin="anonymous"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/config/TeX-AMS-MML_HTMLorMML.js" integrity="sha256-84DKXVJXs0/F8OTMzX4UR909+jtl4G7SPypPavF+GfA=" crossorigin="anonymous"></script><!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]--></head><body data-spy="scroll" data-target="#toc">
<div class="container template-reference-topic">
<header><div class="navbar navbar-default navbar-fixed-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<span class="navbar-brand">
<a class="navbar-link" href="../index.html">shiny</a>
<span class="version label label-default" data-toggle="tooltip" data-placement="bottom" title="">1.10.0.9001</span>
</span>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav"><li>
<a href="../reference/index.html">Reference</a>
</li>
<li>
<a href="../news/index.html">Changelog</a>
</li>
</ul><ul class="nav navbar-nav navbar-right"><li>
<a href="https://github.com/rstudio/shiny/" class="external-link">
<span class="fab fa-github fa-lg"></span>
</a>
</li>
</ul></div><!--/.nav-collapse -->
</div><!--/.container -->
</div><!--/.navbar -->
</header><div class="row">
<div class="col-md-9 contents">
<div class="page-header">
<h1>Slow down a reactive expression with debounce/throttle</h1>
<small class="dont-index">Source: <a href="https://github.com/rstudio/shiny/blob/main/R/reactives.R" class="external-link"><code>R/reactives.R</code></a></small>
<div class="hidden name"><code>debounce.Rd</code></div>
</div>
<div class="ref-description">
<p>Transforms a reactive expression by preventing its invalidation signals from
being sent unnecessarily often. This lets you ignore a very "chatty" reactive
expression until it becomes idle, which is useful when the intermediate
values don't matter as much as the final value, and the downstream
calculations that depend on the reactive expression take a long time.
<code>debounce</code> and <code>throttle</code> use different algorithms for slowing down
invalidation signals; see Details.</p>
</div>
<div id="ref-usage">
<div class="sourceCode"><pre class="sourceCode r"><code><span><span class="fu">debounce</span><span class="op">(</span><span class="va">r</span>, <span class="va">millis</span>, priority <span class="op">=</span> <span class="fl">100</span>, domain <span class="op">=</span> <span class="fu"><a href="domains.html">getDefaultReactiveDomain</a></span><span class="op">(</span><span class="op">)</span><span class="op">)</span></span>
<span></span>
<span><span class="fu">throttle</span><span class="op">(</span><span class="va">r</span>, <span class="va">millis</span>, priority <span class="op">=</span> <span class="fl">100</span>, domain <span class="op">=</span> <span class="fu"><a href="domains.html">getDefaultReactiveDomain</a></span><span class="op">(</span><span class="op">)</span><span class="op">)</span></span></code></pre></div>
</div>
<div id="arguments">
<h2>Arguments</h2>
<dl><dt id="arg-r">r<a class="anchor" aria-label="anchor" href="#arg-r"></a></dt>
<dd><p>A reactive expression (that invalidates too often).</p></dd>
<dt id="arg-millis">millis<a class="anchor" aria-label="anchor" href="#arg-millis"></a></dt>
<dd><p>The debounce/throttle time window. You may optionally pass a
no-arg function or reactive expression instead, e.g. to let the end-user
control the time window.</p></dd>
<dt id="arg-priority">priority<a class="anchor" aria-label="anchor" href="#arg-priority"></a></dt>
<dd><p>Debounce/throttle is implemented under the hood using
<a href="observe.html">observers</a>. Use this parameter to set the priority of
these observers. Generally, this should be higher than the priorities of
downstream observers and outputs (which default to zero).</p></dd>
<dt id="arg-domain">domain<a class="anchor" aria-label="anchor" href="#arg-domain"></a></dt>
<dd><p>See <a href="domains.html">domains</a>.</p></dd>
</dl></div>
<div id="details">
<h2>Details</h2>
<p>This is not a true debounce/throttle in that it will not prevent <code>r</code>
from being called many times (in fact it may be called more times than
usual), but rather, the reactive invalidation signal that is produced by
<code>r</code> is debounced/throttled instead. Therefore, these functions should be
used when <code>r</code> is cheap but the things it will trigger (downstream
outputs and reactives) are expensive.</p>
<p>Debouncing means that every invalidation from <code>r</code> will be held for the
specified time window. If <code>r</code> invalidates again within that time window,
then the timer starts over again. This means that as long as invalidations
continually arrive from <code>r</code> within the time window, the debounced
reactive will not invalidate at all. Only after the invalidations stop (or
slow down sufficiently) will the downstream invalidation be sent.</p>
<p><code>ooo-oo-oo---- =&gt; -----------o-</code></p>
<p>(In this graphical depiction, each character represents a unit of time, and
the time window is 3 characters.)</p>
<p>Throttling, on the other hand, delays invalidation if the <em>throttled</em>
reactive recently (within the time window) invalidated. New <code>r</code>
invalidations do not reset the time window. This means that if invalidations
continually come from <code>r</code> within the time window, the throttled reactive
will invalidate regularly, at a rate equal to or slower than the time
window.</p>
<p><code>ooo-oo-oo---- =&gt; o--o--o--o---</code></p>
</div>
<div id="limitations">
<h2>Limitations</h2>
<p>Because R is single threaded, we can't come close to guaranteeing that the
timing of debounce/throttle (or any other timing-related functions in
Shiny) will be consistent or accurate; at the time we want to emit an
invalidation signal, R may be performing a different task and we have no
way to interrupt it (nor would we necessarily want to if we could).
Therefore, it's best to think of the time windows you pass to these
functions as minimums.</p>
<p>You may also see undesirable behavior if the amount of time spent doing
downstream processing for each change approaches or exceeds the time
window: in this case, debounce/throttle may not have any effect, as the
time each subsequent event is considered is already after the time window
has expired.</p>
</div>
<div id="ref-examples">
<h2>Examples</h2>
<div class="sourceCode"><pre class="sourceCode r"><code><span class="r-in"><span><span class="co">## Only run examples in interactive R sessions</span></span></span>
<span class="r-in"><span><span class="kw">if</span> <span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/interactive.html" class="external-link">interactive</a></span><span class="op">(</span><span class="op">)</span><span class="op">)</span> <span class="op">{</span></span></span>
<span class="r-in"><span><span class="fu"><a href="https://rdrr.io/r/base/options.html" class="external-link">options</a></span><span class="op">(</span>device.ask.default <span class="op">=</span> <span class="cn">FALSE</span><span class="op">)</span></span></span>
<span class="r-in"><span></span></span>
<span class="r-in"><span><span class="kw"><a href="https://rdrr.io/r/base/library.html" class="external-link">library</a></span><span class="op">(</span><span class="va"><a href="https://shiny.posit.co/" class="external-link">shiny</a></span><span class="op">)</span></span></span>
<span class="r-in"><span><span class="kw"><a href="https://rdrr.io/r/base/library.html" class="external-link">library</a></span><span class="op">(</span><span class="va"><a href="https://magrittr.tidyverse.org" class="external-link">magrittr</a></span><span class="op">)</span></span></span>
<span class="r-in"><span></span></span>
<span class="r-in"><span><span class="va">ui</span> <span class="op">&lt;-</span> <span class="fu"><a href="fluidPage.html">fluidPage</a></span><span class="op">(</span></span></span>
<span class="r-in"><span> <span class="fu"><a href="plotOutput.html">plotOutput</a></span><span class="op">(</span><span class="st">"plot"</span>, click <span class="op">=</span> <span class="fu"><a href="clickOpts.html">clickOpts</a></span><span class="op">(</span><span class="st">"hover"</span><span class="op">)</span><span class="op">)</span>,</span></span>
<span class="r-in"><span> <span class="fu"><a href="helpText.html">helpText</a></span><span class="op">(</span><span class="st">"Quickly click on the plot above, while watching the result table below:"</span><span class="op">)</span>,</span></span>
<span class="r-in"><span> <span class="fu"><a href="renderTable.html">tableOutput</a></span><span class="op">(</span><span class="st">"result"</span><span class="op">)</span></span></span>
<span class="r-in"><span><span class="op">)</span></span></span>
<span class="r-in"><span></span></span>
<span class="r-in"><span><span class="va">server</span> <span class="op">&lt;-</span> <span class="kw">function</span><span class="op">(</span><span class="va">input</span>, <span class="va">output</span>, <span class="va">session</span><span class="op">)</span> <span class="op">{</span></span></span>
<span class="r-in"><span> <span class="va">hover</span> <span class="op">&lt;-</span> <span class="fu"><a href="reactive.html">reactive</a></span><span class="op">(</span><span class="op">{</span></span></span>
<span class="r-in"><span> <span class="kw">if</span> <span class="op">(</span><span class="fu"><a href="https://rdrr.io/r/base/NULL.html" class="external-link">is.null</a></span><span class="op">(</span><span class="va">input</span><span class="op">$</span><span class="va">hover</span><span class="op">)</span><span class="op">)</span></span></span>
<span class="r-in"><span> <span class="fu"><a href="https://rdrr.io/r/base/list.html" class="external-link">list</a></span><span class="op">(</span>x <span class="op">=</span> <span class="cn">NA</span>, y <span class="op">=</span> <span class="cn">NA</span><span class="op">)</span></span></span>
<span class="r-in"><span> <span class="kw">else</span></span></span>
<span class="r-in"><span> <span class="va">input</span><span class="op">$</span><span class="va">hover</span></span></span>
<span class="r-in"><span> <span class="op">}</span><span class="op">)</span></span></span>
<span class="r-in"><span> <span class="va">hover_d</span> <span class="op">&lt;-</span> <span class="va">hover</span> <span class="op"><a href="https://magrittr.tidyverse.org/reference/pipe.html" class="external-link">%&gt;%</a></span> <span class="fu">debounce</span><span class="op">(</span><span class="fl">1000</span><span class="op">)</span></span></span>
<span class="r-in"><span> <span class="va">hover_t</span> <span class="op">&lt;-</span> <span class="va">hover</span> <span class="op"><a href="https://magrittr.tidyverse.org/reference/pipe.html" class="external-link">%&gt;%</a></span> <span class="fu">throttle</span><span class="op">(</span><span class="fl">1000</span><span class="op">)</span></span></span>
<span class="r-in"><span></span></span>
<span class="r-in"><span> <span class="va">output</span><span class="op">$</span><span class="va">plot</span> <span class="op">&lt;-</span> <span class="fu"><a href="renderPlot.html">renderPlot</a></span><span class="op">(</span><span class="op">{</span></span></span>
<span class="r-in"><span> <span class="fu"><a href="https://rdrr.io/r/graphics/plot.default.html" class="external-link">plot</a></span><span class="op">(</span><span class="va">cars</span><span class="op">)</span></span></span>
<span class="r-in"><span> <span class="op">}</span><span class="op">)</span></span></span>
<span class="r-in"><span></span></span>
<span class="r-in"><span> <span class="va">output</span><span class="op">$</span><span class="va">result</span> <span class="op">&lt;-</span> <span class="fu"><a href="renderTable.html">renderTable</a></span><span class="op">(</span><span class="op">{</span></span></span>
<span class="r-in"><span> <span class="fu"><a href="https://rdrr.io/r/base/data.frame.html" class="external-link">data.frame</a></span><span class="op">(</span></span></span>
<span class="r-in"><span> mode <span class="op">=</span> <span class="fu"><a href="https://rdrr.io/r/base/c.html" class="external-link">c</a></span><span class="op">(</span><span class="st">"raw"</span>, <span class="st">"throttle"</span>, <span class="st">"debounce"</span><span class="op">)</span>,</span></span>
<span class="r-in"><span> x <span class="op">=</span> <span class="fu"><a href="https://rdrr.io/r/base/c.html" class="external-link">c</a></span><span class="op">(</span><span class="fu">hover</span><span class="op">(</span><span class="op">)</span><span class="op">$</span><span class="va">x</span>, <span class="fu">hover_t</span><span class="op">(</span><span class="op">)</span><span class="op">$</span><span class="va">x</span>, <span class="fu">hover_d</span><span class="op">(</span><span class="op">)</span><span class="op">$</span><span class="va">x</span><span class="op">)</span>,</span></span>
<span class="r-in"><span> y <span class="op">=</span> <span class="fu"><a href="https://rdrr.io/r/base/c.html" class="external-link">c</a></span><span class="op">(</span><span class="fu">hover</span><span class="op">(</span><span class="op">)</span><span class="op">$</span><span class="va">y</span>, <span class="fu">hover_t</span><span class="op">(</span><span class="op">)</span><span class="op">$</span><span class="va">y</span>, <span class="fu">hover_d</span><span class="op">(</span><span class="op">)</span><span class="op">$</span><span class="va">y</span><span class="op">)</span></span></span>
<span class="r-in"><span> <span class="op">)</span></span></span>
<span class="r-in"><span> <span class="op">}</span><span class="op">)</span></span></span>
<span class="r-in"><span><span class="op">}</span></span></span>
<span class="r-in"><span></span></span>
<span class="r-in"><span><span class="fu"><a href="shinyApp.html">shinyApp</a></span><span class="op">(</span><span class="va">ui</span>, <span class="va">server</span><span class="op">)</span></span></span>
<span class="r-in"><span><span class="op">}</span></span></span>
<span class="r-in"><span></span></span>
</code></pre></div>
</div>
</div>
<div class="col-md-3 hidden-xs hidden-sm" id="pkgdown-sidebar">
<nav id="toc" data-toggle="toc" class="sticky-top"><h2 data-toc-skip>Contents</h2>
</nav></div>
</div>
<footer><div class="copyright">
<p></p><p>Developed by Winston Chang, Joe Cheng, JJ Allaire, Carson Sievert, Barret Schloerke, Yihui Xie, Jeff Allen, Jonathan McPherson, Alan Dipert, Barbara Borges, Posit Software, PBC.</p>
</div>
<div class="pkgdown">
<p></p><p>Site built with <a href="https://pkgdown.r-lib.org/" class="external-link">pkgdown</a> 2.1.3.</p>
</div>
</footer></div>
</body></html>