Debouncing sources
By default, Autocomplete offers as-you-type search and processes sources for each keystroke: a real-time experience with instant feedback. However, there are situations when as-you-type might not be desirable or even possible.
Debouncing helps prevent too many requests by waiting for a pause in activity. Debouncing can help in these cases:
- Avoid sending too many requests in a short period. When using rate-limited services like the GitHub API, sending frequent requests can cause errors.
- Accommodate users who prefer reduced UI motion. As-you-type search results can change the UI rapidly.
- Anticipate typing speed. By carefully selecting an appropriate debounce delay for your audience, you can significantly reduce the number of search requests while maintaining a good user experience.
Write a debouncing function
To tell Autocomplete to “wait” for a set time after typing stops before returning results, write a debouncing function that returns a promise. When the timeout elapses, the promise for the passed items is resolved.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import { autocomplete } from '@algolia/autocomplete-js';
function debouncePromise(fn, time) {
let timer = undefined;
return function debounced(...args) {
if (timer) {
clearTimeout(timer); // Clear the timeout first if it's already defined.
}
return new Promise((resolve) => {
timer = setTimeout(() => resolve(fn(...args)), time);
});
};
}
The debouncePromise
function lets you create a wrapper around any asynchronous function and delay it for a specified time:
300 ms in the example.
1
const debounced = debouncePromise((items) => Promise.resolve(items), 300);
Select a debounce delay
The optimal debouncing delay matches your audience’s typing speed. If the delay is too short, users still see flashes of content. If the delay is too long, the feedback loop for users becomes too long. The faster users type, the shorter the debouncing delay has to be.
Words per minute | Suggested debounce delay (ms) |
---|---|
30 | 400 |
40 | 300 |
50 | 240 |
60 | 200 |
70 | 170 |
80 | 150 |
Debounce sources
Use the debounced
function for static and dynamic sources.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// ...
autocomplete({
container: '#autocomplete',
getSources({ query }) {
return debounced([
{
sourceId: 'algoliaItems',
getItems() {
return getAlgoliaResults({
searchClient,
queries: [
{
indexName: 'indexName',
query,
},
],
});
},
// ...
},
{
sourceId: 'staticItems',
getItems({ query }) {
const items = [
{ label: 'Twitter', url: 'https://twitter.com' },
{ label: 'GitHub', url: 'https://github.com' },
];
return items.filter(({ label }) =>
label.toLowerCase().includes(query.toLowerCase())
);
},
// ...
},
{
sourceId: 'dynamicItems',
getItems() {
return fetch(`https://example.org/search/?q=${query}`)
.then((response) => response.json())
.then(({ results }) => results)
.catch(() => []);
},
// ...
},
]);
},
});