I have the following JavaScript code and noticed the stack is growing indefinitely.
https://jsfiddle.net/uok7vz9b/
(function () {
async function poll() {
try {
// await fetch ...
} catch (err) {
console.error("Error: ", err);
} finally {
console.trace();
start();
}
}
function start() {
setTimeout(poll, 2000);
}
document.addEventListener("DOMContentLoaded", poll, {once: true});
})();
First output is:
console.trace() _display:118:15
poll https://fiddle.jshell.net/_display/?editor_console=true:118
(Async: EventListener.handleEvent)
<anonymous> https://fiddle.jshell.net/_display/?editor_console=true:127
<anonymous> https://fiddle.jshell.net/_display/?editor_console=true:128
Second output:
console.trace() _display:118:15
poll https://fiddle.jshell.net/_display/?editor_console=true:118
(Async: setTimeout handler)
start https://fiddle.jshell.net/_display/?editor_console=true:124
poll https://fiddle.jshell.net/_display/?editor_console=true:119
(Async: EventListener.handleEvent)
<anonymous> https://fiddle.jshell.net/_display/?editor_console=true:127
<anonymous> https://fiddle.jshell.net/_display/?editor_console=true:128
... and so on.
I don't really understand why, because I though setTimeout
does not block and just starts a new timer. So I expected the poll
function to finish, and then it is fired again with a clean stack.
I have looked around and not really found any good examples for "execute function once on page load and then periodically". I don't want to use setInterval
because long running AJAX calls could then exceed the timeout. But the timeout should rather be the minimum time between two calls of poll
.
This is a result of async stack traces. I have no idea if it's possible to blow the async stack or whether there are measures in the browser to limit the depth of the async stack preventing overflow/leaks.
While the following code does the same thing:
(function() {
const delay = (duration) => new Promise(r => setTimeout(() => r(), duration))
async function poll() {
for (;;) {
try {
// await fetch ...
} catch (err) {
console.error("Error: ", err);
} finally {
console.trace();
}
await delay(2000)
}
}
document.addEventListener("DOMContentLoaded", poll, {
once: true
});
})();
It does not add to the async stack.