How can I efficiently debounce a search input with async calls in JavaScript?

I’m building a search feature in a web application using vanilla JavaScript, where users type in a search query, and the app sends an asynchronous API request after a delay, to avoid excessive calls while the user is typing.

I want to debounce the input so that the API is only called after the user has stopped typing for a specified time (e.g., 500ms), but I also need to handle the asynchronous nature of the API calls efficiently.

const searchInput = document.getElementById('search-input');
let timeoutId;

searchInput.addEventListener('input', function(event) {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => {
    searchAPI(event.target.value);
}, 500);
});

async function searchAPI(query) {
const response = await fetch(`https://api.example.com/search?q=${query}`);
const results = await response.json();
console.log(results);
}

How can I improve this code to ensure that:

Only one request is sent after the user has stopped typing for the specified delay.
If a new input comes in before the timeout expires, the previous request is canceled.
The solution is efficient, considering both performance and network usage.
I’d appreciate any suggestions for optimizing this debounce function while keeping it simple and working well with async/await.

Thanks in advance!