직원이 고객사 이름을 한글로 검색합니다. 자음 하나를 누를 때마다 결과가 바뀌고, 완성한 뒤에도 이전 검색 결과가 다시 나타납니다. 영문 검색만 테스트했을 때는 보이지 않던 문제입니다. 한글 입력은 IME 입력기를 통해 글자를 조합한 뒤 확정하며, 브라우저는 조합 중간에도 입력 관련 이벤트를 발생시킬 수 있습니다. 여기에 네트워크 응답이 입력 순서와 다르게 도착하는 문제가 더해집니다. 실시간 검색은 조합 중인 값, 확정된 값, 최신 요청을 따로 다뤄야 안정적입니다.
입력 이벤트가 곧 완성된 검색어는 아니다
검색창의 값이 바뀌었다는 사실만으로 즉시 조회하면 한글 한 음절을 만드는 중간 상태마다 서버에 요청을 보낼 수 있습니다. 조합 시작과 종료를 알리는 이벤트를 관찰하고, 조합 중에는 조회를 잠시 보류하거나 화면에 나타난 입력값만 갱신합니다. MDN의 compositionend 안내는 입력기 조합이 완료되거나 취소될 때 이 이벤트가 발생한다고 설명합니다. InputEvent.isComposing도 조합 상태를 확인하는 데 쓸 수 있지만 구형 환경의 호환성을 점검하고 composition 이벤트를 함께 다루는 편이 안전합니다.
조합이 끝난 직후에도 브라우저와 입력기 조합에 따라 관련 input 이벤트가 이어질 수 있습니다. 따라서 ‘조합 종료’와 바로 뒤 input 이벤트에서 같은 검색어를 두 번 보내지 않도록 마지막 확정 검색어를 비교합니다. 붙여넣기와 음성 입력, 모바일 키보드 자동 수정은 조합 이벤트 없이도 값이 바뀔 수 있으므로 input 자체를 무시해서는 안 됩니다. 최종 검색 실행 함수 하나를 만들고 모든 입력 경로가 그 함수를 호출하게 하면 중복과 누락을 줄일 수 있습니다.

디바운스는 요청량을 줄이지 응답 순서를 보장하지 않는다
사용자가 입력을 멈춘 뒤 짧은 대기 시간을 두는 디바운스는 서버 요청을 줄입니다. 하지만 먼저 보낸 ‘김’ 검색이 느리고 나중에 보낸 ‘김철’ 검색이 빠르면 최신 결과가 표시된 뒤 오래된 ‘김’ 결과가 도착해 화면을 덮을 수 있습니다. 요청마다 증가하는 번호나 검색어 스냅샷을 붙이고, 응답을 반영할 때 현재 입력의 최신 요청인지 검사합니다. 이전 요청을 취소하는 AbortController도 도움이 되지만 취소 신호가 서버 작업까지 되돌리는 것은 아니며 이미 도착한 응답과의 경합을 모두 없애지도 않습니다. 최신 응답만 반영하는 검사가 핵심입니다.
빈 검색어의 동작도 명확히 정합니다. 전체 목록을 보여 줄지, 최근 검색을 보여 줄지, 아무 결과도 보여 주지 않을지 제품 목표에 따라 선택합니다. 공백과 대소문자, 유니코드 정규화 방식은 클라이언트와 서버가 같은 기준을 사용해야 합니다. 검색어가 URL에 들어가는 경우에는 고객 이름이나 개인정보가 주소 기록과 분석 로그에 남을 수 있으므로 저장 정책을 고려합니다. 검색 결과의 ‘없음’은 입력이 완료되기 전 잠깐 나타난 상태인지, 실제 검색 결과가 없는지 구분해야 사용자가 혼란스럽지 않습니다.
Enter 키는 조합 확정에 사용될 수도 있습니다. 조합 중 Enter를 무조건 ‘검색 실행’으로 처리하면 글자를 확정하려던 사용자가 의도치 않게 화면을 이동합니다. 검색창에서 키보드 단축키를 구현할 때는 조합 상태를 확인하고, 확정 후 Enter와 조합용 Enter를 구별해 보세요. 자동완성 항목을 화살표로 선택하는 기능도 조합 중에는 섣불리 포커스를 바꾸지 않도록 합니다.

테스트는 실제 한글 입력기로 한다
자동 테스트가 input 값에 완성된 한글 문자열을 바로 넣기만 하면 조합 문제를 놓칩니다. Windows와 macOS의 한글 입력기, Android와 iOS 키보드에서 글자 입력·삭제·붙여넣기·자동 수정을 시험하세요. 느린 네트워크를 흉내 내 오래된 응답이 마지막에 오는 순서도 확인합니다. 화면 읽기 도구 사용자를 위해 결과 개수를 지나치게 자주 알리지 않고, 검색창의 키보드 포커스가 결과 갱신 때문에 이동하지 않게 합니다. 좋은 실시간 검색은 한 글자마다 가장 빨리 반응하는 기능이 아니라 사용자가 확정한 질문의 최신 답을 안정적으로 보여 주는 기능입니다.