From 479d3959e65bf96db879c3901f0f7dd0a6b545e0 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 11 Feb 2026 21:15:42 +0000 Subject: [PATCH] feat(perf): fix race condition in domain search - Introduced `lastRequestId` to track and discard stale search requests. - Optimized search trigger using reactive statement `$: domainName, debounce()` instead of `on:keyup` to cover all input methods. - Updated `debounceTimer` type to `ReturnType` for better type safety. This prevents the UI from displaying incorrect search results if a previous request completes after a newer one, and improves input responsiveness. Co-authored-by: Yeboster <23556525+Yeboster@users.noreply.github.com> --- .jules/bolt.md | 3 +++ src/routes/DomainSearch.svelte | 16 ++++++++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) create mode 100644 .jules/bolt.md diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..345882d --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-10-25 - Race Condition in Async Search +**Learning:** Async search functions triggered by user input can cause race conditions where a stale response overwrites a fresh one. Using a request ID counter and capturing local state is a robust fix. +**Action:** Always implement a request ID or cancellation token for typeahead search components. diff --git a/src/routes/DomainSearch.svelte b/src/routes/DomainSearch.svelte index 2cde1b3..aa0a0c9 100644 --- a/src/routes/DomainSearch.svelte +++ b/src/routes/DomainSearch.svelte @@ -15,8 +15,10 @@ let domainName: string = ''; let nameSearched: string = ''; let isLoading: boolean = false; - let debounceTimer: NodeJS.Timeout; + let debounceTimer: ReturnType; + let lastRequestId = 0; + $: domainName, debounce(); $: errors = invalid ? validator.getErrors() : []; $: invalid = domainName !== '' && !validator.validate(domainName, { raiseError: false }); $: nameSearchedLabel = nameSearched ? `${nameSearched}.${$metaNamesSdk.config.tld}` : null; @@ -36,11 +38,18 @@ return goto(url); } - nameSearched = domainName.toLocaleLowerCase(); + const requestId = ++lastRequestId; + const currentName = domainName.toLocaleLowerCase(); + nameSearched = currentName; isLoading = true; - domain = await $metaNamesSdk.domainRepository.find(domainName); + // Capture the result in a local variable to avoid race conditions + const result = await $metaNamesSdk.domainRepository.find(currentName); + // If a new request has started since this one, ignore the result + if (requestId !== lastRequestId) return; + + domain = result; isLoading = false; } @@ -55,7 +64,6 @@ class="domain-input" variant="outlined" bind:value={domainName} - on:keyup={() => debounce()} bind:invalid label="Domain name" withTrailingIcon