Improve polling using setTimeOut
Thu Nov 12 2020 🍵 0 min read
setTimeOut
and setInterval
are very similar in that they perform an action after a given time period. The difference is that setTimeOut
executes the function only once. Polling requires that you execute an action/function after a given interval. It is very common to implement polling using the window setInterval
property.
For example:
let interval = 0;
function action() {
console.log('do something here')
}
function poll() {
interval = setInterval(() => {
action()
}, 10000)
}
function clear() {
clearInterval(interval)
}
poll()
The implementation above is simple, clear, and efficient. It ensures that the action
is performed every 10 seconds. However, if the action is a request to the server and the server is slow, you could have multiple requests pending because setInterval
will execute after the given time has elapsed, whether the previous call has been completed or not. We can mitigate this issue easily using setTimeout
.
function action() {
// mimic slow server
return new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('do something here')
}, 10000)
})
}
function poll() {
interval = setTimeout(async () => {
await action()
poll()
}, 10000)
}
Now we will only poll the action again after the previous one has been completed.
Bonus
You might want to poll the action
only if the page is visible to the user or the browser tab is active. This is where window event listener visibilitychange
comes in handy. visibilitychange
is triggered each time the browser tab is active or inactive. In the handler of the event listener, you can check for the browser tab visible using document.hidden
or document.visibilityState
.
For example:
document.addEventListener("visibilitychange", function() {
if (document.hidden) {
clear()
} else {
poll()
}
});
Pretty simple!
Here's the full code for you to try out:
let interval = 0;
function action() {
// mimic slow server
return new Promise(function (resolve, reject) {
setTimeout(() => {
resolve('do something here')
}, 10000)
})
}
function poll() {
interval = setTimeout(async () => {
const response = await action()
console.log(response)
poll()
}, 10000)
}
function clear() {
clearInterval(interval)
}
document.addEventListener("visibilitychange", function() {
if (document.hidden) {
clear()
} else {
poll()
}
});
poll()