I originally said "This will fill the memory infinitely.",
but according to many comments I have to consider that I'm probably wrong !
So I deleted the original answer. I only keep this answer for now so that the comments (and the ability to add comments) are not lost.
I'll also keep my "experiments" here, which might help to illustrate what's happening.
Example without await
Consider the equivalent using .then()
instead of await
, which I think is easier to follow:
// without-await.js
function recurse() {
return someAsyncStuff().then( function(){
return recurse();
});
}
(async function(){
await recurse(0);
})();
Example with immediately resolved promise
You can confirm the memory leak if you replace await someAsyncStuff()
by await Promise.resolve()
,
which will fill the memory quickly:
// immediately-resolved.js
async function recurse() {
await Promise.resolve();
return recurse();
}
(async function(){
await recurse(0);
})();
What someAsyncStuff()
does
Also note that (at least for me) it makes a big difference what someAsyncStuff()
actually does.
E.g. with a setTimeout
my memory does fill, but very slowly:
function someAsyncStuff() {
return new Promise( function(resolve, reject){
setTimeout( resolve, 0 );
//resolve();
});
}
With an immediately resolved Promise on the other hand the memory will fill very quickly:
function someAsyncStuff() {
return new Promise( function(resolve, reject){
//setTimeout( resolve, 0 );
resolve();
});
}
My conclusions
Again, my ideas are not to be considered an answer anymore!
My conclusion was that not the call stack would leak, but something about the Promises
(I originally said the microtask queue, but according to the comments that's wrong,
which makes sense to me, but then there must be something else ? (the "database" ?)).
Not the call stack
The call stack doesn't fill recursively:
recurse()
is executed and pushed to the call stack
someAsyncStuff()
is executed and pushed to the call stack
someAsyncStuff()
creates and returns a pending promise
someAsyncStuff()
is popped off the call stack
recurse()
returns that pending Promise
recurse()
is popped off the call stack
- The stack is empty, the promise is in memory