You are in a recursive loop and should avoid using nested setInterval
. This method will lead to an excessive number of interval instances. Instead of utilizing setInterval
, it is advised to schedule additional requests using setTimeout
.
setInterval
will continuously fire at specified intervals until manually stopped.
setTimeout
fires only once.
Let's take a look at the following code, which aims to resolve some of the issues seen in this question as well as your other two questions.
Firstly, as mentioned earlier, refrain from using setInterval
unless you intend for it to run indefinitely. Furthermore, avoid nesting the creation of setInterval
unless specifically required.
Instead, let's develop a recursive function called getTimeLeft()
that will manage sending the request and scheduling the next time check after a certain duration.
This example also simulates the $.ajax()
function so you can observe the function in operation without having access to an actual backend.
// Simulated server-side data for tracking remaining time
const timeLefts = {
foo: 0,
bar: 0,
fizz: 0,
buzz: 0
};
const timeLeftsUpdateInterval = setInterval(() => {
for (const [key, val] of Object.entries(timeLefts)) {
timeLefts[key] = Math.min(val + Math.random() * 10, 100);
}
if (Object.entries(timeLefts).every(([k, v]) => v >= 100)) {
clearInterval(timeLeftsUpdateInterval);
}
}, 1000);
// Mock $.ajax function for emulating AJAX requests
function $ajax(kwargs) {
return {
done: cb => {
setTimeout(() => {
cb(timeLefts[kwargs.data.x]);
}, 500);
}
};
}
// Check for updates every second after completion of the last request
const timeLeftCheckInterval = 1000;
// Continuously monitor remaining time for an element
function getTimeLeft(el) {
// Prepare request data
const dataString = {
s: "<?echo $_SESSION['currentview_'.$stamp]?>",
r: "<?echo $search_usernumber?>",
st: "<?echo $stamp?>",
// Custom property for functionality
x: el.dataset.item
};
// Send request to retrieve remaining time
const req = $ajax({ // Utilizing our mock $.ajax
type: "POST",
url: "get_content_home.php",
dataType: "html",
data: dataString
});
// Upon completion of the request
req.done(data => {
// Update the element with the remaining time
el.innerHTML = data;
// Implement condition to cease checking for time indefinitely
// Eventually, there won't be any time left, right? So why keep checking?
if (data.timeleft <= 0) return;
// Schedule the next round of time checking after a specific duration
setTimeout(() => {
getTimeLeft(el);
}, timeLeftCheckInterval);
});
}
// Initiate the process of obtaining remaining time for all .items
Array.from(document.querySelectorAll(".item"))
.forEach(el => getTimeLeft(el));
<ul>
<li class="item" data-item="foo"></li>
<li class="item" data-item="bar"></li>
<li class="item" data-item="fizz"></li>
<li class="item" data-item="buzz"></li>
</ul>
This code resolves the issue raised in 2 Ajax non-blocking by providing each element with its logic for fetching time left and updating itself.
It also tackles the potential issue discussed in Timer in Ajax - Preemption ensuring that elements won't recheck the remaining time until the previous check completes.