-
Notifications
You must be signed in to change notification settings - Fork 149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Debounce source
function by debounceMs
on keystroke
#611
Conversation
973b7e0
to
a2915ea
Compare
debounceMs
source
function by debounceMs
on keystroke
54702a4
to
32655c7
Compare
I have rebased this onto #612 locally; integration tests do pass. I've added an example for |
Pausing this; looks like |
Thanks @rgarner I've split out the WebdriverIO v8 upgrade into #615 since the breaking changes go a step beyond maintenance The package updates in #612 should be a relatively stable base now and drop |
@colinrotherham thanks again for all this. I know how intense and discursive this sort of work is, so it's really appreciated. I just rebased this onto the latest
|
@rgarner Ah hopefully your README suggestion will come in handy now The Node.js version in .nvmrc is now the latest LTS release so |
I did notice iron over fermium but I just didn't notice enough this late in the day to think that through, thanks 😃 |
@colinrotherham I've updated this after having rebased it onto |
On the basis that this works on the |
Status is using it, but autocomplete will be in a moment.
When debounceMs is greater than 0, delay the calling of the `source` function for that number of milliseconds. In the circumstance where the `source` function is talking to an API with a potentially large result set – the querying of which has potential to overload hosting – even a modest value of 200ms or so can halve or quarter the number of queries each user sends without appreciably degrading their experience. When debounceMs is 0, pass the `source` function through unchanged. This commit should not change the behaviour of any existing consumer.
When a `source` query has yet to be called, it's not necessary to show "no results found". Pass the debouncing state of the autocomplete down to the Status component through Status.props.autocompleteDebouncing such that the status component does not announce "no results available" immediately before announcing "50 results available". From the autocomplete, this is difficult to test. Tests already exist showing that `this.state.debouncing` is set appropriately when `debounceMs` is in use. It is used in conjunction with the `showNoOptionsFound` prop to suppress tNoResults in render(). No good option exists for testing it that doesn't involve extra redundant state to service the tests. It can't be done by rendering tests alone, and it can't be done by behaviour tests alone.
ad23c7c
to
c99546e
Compare
Given this a rebase with |
@colinrotherham many thanks indeed, I would not have had your level of understanding |
Hi @rgarner, Thanks for proposing this and calling our attention to debouncing when loading from a server! While reviewing it, I've noticed that your changes introduce a little glitch in the UI, displaying a thicker border when the user starts typing on an empty field. Looks like the listbox containing the results becomes made visible staight away, but because the calls are debounced, the message gets hidden until results actually come back. This is probably better seen than described, so I've captured two recordings (one with a silly long timeout to have enough time to see what happens). The quick debounce: Kapture.2024-01-18.at.11.59.46.mp4The longer delay Kapture.2024-01-18.at.12.40.11.mp4While an option would be to update the check that makes the listbox visible to account for the As an alternative, I've explored what was already possible in terms of debouncing with the current state of the project. With the help of the On top of providing feedback that results are loading and debouncing to not put servers on their knees (and avoid wasting requests while users are typing), there are also other concerns to handle when fetching suggestions from a server:
With the debouncing happening inside the component, this becomes a little trickier to add. And like the feedback and loading, it seems it can all be dealt with by crafting the function fetching the results appropriately, which would allow not to expand the responsibilities of the component. Kapture.2024-01-18.at.18.29.35.mp4Would you be able to confirm if the implementation in this example on the debounced-ajax-example branch would have been suitable for reducing the load of your server or let us know were the gaps would be? |
Hi @romaricpascal — thanks for the videos and the example, they're super helpful. I noticed the same thing with the border when testing our fork in our project. We hedged our bets and connect() {
this._id = this.textfieldTarget.id
this.handleQueryDebounced = debounce(async (query, populateResults) => {
await this.handleQuery(query, populateResults);
}, this.debounceMsValue);
this.debouncedSource = async (query, populateResults) => {
this.#debouncing = true;
try {
await this.handleQueryDebounced(query, populateResults);
} finally {
this.#debouncing = false;
}
}
accessibleAutocomplete({
element: this.autocompleteRootTarget,
id: this.textfieldTarget.id, // To match it to the existing <label>.
defaultValue: this.textfieldTarget.value,
source: this.debouncedSource.bind(this),
onConfirm: this.lookupSelected.bind(this),
minLength: this.minLengthValue,
tNoResults: () => this.#debouncing ? this.searchingValue : this.noResultsValue,
templates: {
suggestion: this.renderSuggestion.bind(this)
}
})
this.textfieldTarget.id = null
this.autoCompleteInput.addEventListener('input', () => this.clearLookupId())
this.searching = this.lookupIdBlank() && this.lookupNameBlank() && this.noErrorMessages()
}
I don't see any gaps, it was pretty nice to implement with the args already available to us. The only real "gap" as such we've noticed (and this could easily be another thing I missed) are not at all debounce-related. They're that the component doesn't report certain events we'd be interested in as they arrive at the internal Given the glitches you've noticed — and the complexity of having two debounces (one for Thanks hugely for your time, it's very much appreciated — even if they never make it to |
When
debounceMs
is greater than 0, delay the calling of thesource
function for that number of milliseconds. In the circumstance where the
source
function is talking to an API with a potentially large resultset – the querying of which has potential to overload hosting – even
a modest value of 300ms or so can halve or quarter the number of
queries each user sends without appreciably degrading their experience.
When
debounceMs
is 0, pass thesource
function through unchanged.This commit should not change the behaviour of any existing consumer.
Don't display the
tNoResults
message while debounce is happening, and likewisesilence the Status announcer to avoid "no results available" occurring back to back
with "50 results available".
Caveat
I've been running the functional tests developing this. I'm unable to run the integration tests locally; they all fail with async errors of the form