Reputation: 151196
I wonder what a good way is to ignore earlier but delayed AJAX data return, when a newer AJAX call should be taken care of instead?
For example, if the first data fetch that started at 12:01:33 is delayed and returns at 12:01;39, and the second data fetch that started at 12:01:36 actually came back first, at 12:01:38. So the data returned at 12:01:39 should not be honored and should not be displayed onto the webpage and "cover up" the result of the second data fetch.
In some case, we might disable the Search or Submit button so that the user cannot click on the button again, but what about if there is a text input box, and the user typed "React" and press Enter, but he changed his mind and added "Redux" to the search box and pressed Enter again, and results returned by the "React" search should then be ignored (for both of the cases if this first AJAX returns either before or after the second AJAX), and only results returned by "React Redux" should be taken care of, to populate into the search result area down below.
In my past jobs, it seems that nobody actually took care of things like this. I can think of one way, which is:
let fetchTimeStampToHonor;
function getData() {
let currentFetchTimestamp = Date.now();
fetchTimeStampToHonor = currentFetchTimestamp;
fetch("...")
.then(res => res.json())
.then(data => {
if (currentFetchTimestamp === fetchTimeStampToHonor) { // honor it
}
});
}
so that if there is a newer call to getData()
, then fetchTimeStampToHonor
will get updated to the newest currentFetchTimestamp
. The function passed to then
is a closure and is able to access the local currentFetchTimestamp
, and can be compared with fetchTimeStampToHonor
. But the code above involves a global variable, which I can hide if I use a function to return getData()
, and this way, I can hide fetchTimeStampToHonor
inside of local scope and make it private. (but I think if this is inside of a module, it is private to the module and isn't such a big problem). Or it might be able to be made into some state if it is in ReactJS.
But are there some other better solutions?
Upvotes: 0
Views: 186
Reputation: 3072
You could produce a local cache of results. Use the search term as the key, then only show the relevant results. The code below is far from optimised and I would NOT use it as is, but I hope it illustrates the point.
I've used react in the example as it provides an easy way to show stateful changes but this concept could be done with raw JS as well.
const App = () => {
const [searchTerm, setSearchTerm] = useState('')
const [dataCache, setDataCache] = useState({})
useEffect(() => {
fetch(`search?term=${searchTerm}`)
.then((res) => res.json())
.then((data) => {
setDataCache((prev) => ({
...prev,
[searchTerm]: data,
}))
})
}, [searchTerm])
return (
<>
<input type="search" onChange={(e) => setSearchTerm(e.target.value)} />
<Results data={dataCache[searchTerm]} />
</>
)
}
Upvotes: 1