Как оптимизировать код при отправке запроса на каждый символ ввода
Что проверяют
Умеете ли вы снизить нагрузку от поиска по мере ввода и понимаете ли, что одного debounce мало: остаются гонки ответов и повторные запросы. Следом часто просят написать debounce руками или спрашивают, что будет, если ответ на старый запрос придёт позже нового.
Как отвечать
Решение складывается из нескольких слоёв:
- debounce: запрос уходит, только когда пользователь перестал печатать на заданное время, обычно от 250 до 400 мс. Для поиска это основной инструмент;
- throttle: не чаще одного вызова за интервал. Подходит для скролла и ресайза, для поиска хуже: промежуточные запросы всё равно уйдут;
- отмена устаревших запросов:
AbortControllerпередаётся вfetch, и при новом вводе предыдущий запрос отменяется черезabort(). Без этого ответ на «re» может прийти после ответа на «react» и перезаписать результаты; - отсечение лишнего: минимальная длина запроса в две или три буквы,
trim(), пропуск запроса, если строка не изменилась; - кеш: результаты по ключу запроса в
Mapс ограничением размера, либо TanStack Query или SWR, где ключ запроса сам даёт кеш, дедупликацию и отмену.
В RxJS та же схема записывается цепочкой debounceTime(300), distinctUntilChanged(), switchMap(): последний оператор сам отписывается от предыдущего запроса.
В React функция с задержкой должна создаваться один раз: через useMemo или useRef, с отменой таймера в очистке useEffect. Альтернатива: хранить введённое значение в состоянии и дебаунсить само значение в эффекте. useDeferredValue здесь не замена: он откладывает рендер, но не сокращает число запросов.
Где спотыкаются
Создают debounce(...) прямо в теле компонента. На каждом рендере получается новая функция со своим таймером, и задержка не работает.
Считают, что debounce решает гонки. Он уменьшает число запросов, но два запроса всё равно могут вернуться в обратном порядке, если их не отменять и не сверять ответ с текущим значением поля.
Путают debounce и throttle или выбирают задержку наугад. Слишком большая делает поиск «тормозным», слишком маленькая почти ничего не экономит, значение подбирают по ощущениям пользователей и метрикам нагрузки.