Skip to content

Commit aaea7b3

Browse files
keithamuskoddsson
andcommitted
remove section on debouncing with signals
Co-authored-by: Kristján Oddsson <[email protected]>
1 parent a300510 commit aaea7b3

File tree

1 file changed

+0
-109
lines changed

1 file changed

+0
-109
lines changed

learn/techniques/signals-and-cancellation.md

-109
Original file line numberDiff line numberDiff line change
@@ -262,112 +262,3 @@ class SearchInputElement extends HTMLInputElement {
262262
}
263263
}
264264
```
265-
266-
### Using signals to debounce or throttle methods
267-
268-
_Debouncing_ or _Throttling_ are techniques whereby you delay an action for a fixed time period, discarding any events
269-
between them. These techniques are useful within UI as a way to delay an expensive operation like a network fetch or
270-
something CPU intensive like sorting many items. Consider a list filter input, that shows and hides thousands of items
271-
depending on if they match the text input.
272-
273-
As debouncing & throttling are based on time, an `AbortController` isn't needed. Timeouts are such a common pattern that
274-
`AbortSignal.timeout()` can be used as a quick way to create a signal that will abort after some time has passed.
275-
276-
Throttling and debouncing are variations on the same broader concept of limiting the times an action gets executed. If
277-
you're calling a function 10 times in a row, at 50ms intervals, a throttle of 100ms would ensure that the action is only
278-
run every 100ms, whereas a debounce would defer each call until there hadn't been one for more 100ms or more. To
279-
illustrate this concept we can look at a timeline:
280-
281-
```
282-
|-----|-----|-----|-----|-----|-----|-----|-----|
283-
Source 50 100 200 250 350 400
284-
throttle(100) 100 200 350
285-
debounce(100) 100 250 400
286-
```
287-
288-
You can think of throttling as disregarding some calls but acting on others, whereas debounce waits for quiet periods.
289-
To throttle a method, you'll create the signal every time it is aborted, and execute the behavior when the timer has
290-
aborted:
291-
292-
```js
293-
class ListFilterInputElement extends HTMLInputElement {
294-
static define(tag = "list-filter-input") {
295-
customElements.define(tag, this, { extends: "input" })
296-
}
297-
298-
connectedCallback() {
299-
this.addEventListener("input", this)
300-
}
301-
302-
timeout = 100
303-
304-
#throttleSignal = null
305-
306-
handleEvent() {
307-
// Don't do anything if the timer has yet to time out
308-
if (this.#throttleSignal && !this.#throttleSignal.aborted) return
309-
310-
// The time has been aborted, so make a new timer for next time
311-
this.#throttleSignal = AbortSignal.timeout(this.timeout)
312-
313-
// Execute the action
314-
this.filer()
315-
}
316-
317-
filter() {
318-
for (const el of this.list.children) {
319-
el.hidden = el.textContent.includes(this.input)
320-
}
321-
}
322-
}
323-
```
324-
325-
_Debouncing_ would add a **delay** and so needs to act on the timeout happening, not some time after. Using the
326-
`aborted` event can queue up work for when the timer ends:
327-
328-
```js
329-
class ListFilterInputElement extends HTMLInputElement {
330-
static define(tag = "list-filter-input") {
331-
customElements.define(tag, this, { extends: "input" })
332-
}
333-
334-
connectedCallback() {
335-
this.addEventListener("input", this)
336-
}
337-
338-
timeout = 100
339-
340-
#debounceSignal = null
341-
342-
async handleEvent() {
343-
// Don't do anything if the timer has run out
344-
if (this.#debounceSignal?.aborted) return
345-
346-
// Renew the signal
347-
this.#debounceSignal = AbortSignal.timeout(this.timeout)
348-
349-
// Schedule work for after debouncement
350-
this.#debounceSignal.addEventListener(
351-
"abort",
352-
(event) => {
353-
// Check to see that new work hasn't been scheduled
354-
if (event.target === this.#debounceSignal) {
355-
// Clear out the signal so new work can be schedule
356-
this.#debounceSignal = null
357-
358-
// Execute the action
359-
this.filter()
360-
}
361-
},
362-
{ once: true }
363-
)
364-
}
365-
366-
filter() {
367-
for (const el of this.list.children) {
368-
el.hidden = el.textContent.includes(this.input)
369-
}
370-
}
371-
}
372-
```
373-

0 commit comments

Comments
 (0)