this question is not new on SO, but I have a scenario that is not exactly the same as other questions.
Let’s say I have a class Component
class Component {
constructor() {
this.resolvers = [];
}
addResolver() {
return new Promise((resolve) => {
this.resolvers.push(resolve);
});
}
callResolvers() {
this.resolvers.forEach((resolver) => resolver());
}
}
Then I have this snippet of code
let components = [];
async function addComponent() {
const component = new Component();
components.push(component);
await component.addResolver();
console.log("resolver called");
}
function deleteComponents() {
components = [];
}
function resolveComponents() {
components.forEach((component) => component.callResolvers());
}
addComponent();
addComponent();
addComponent();
resolveComponents();
If I call resolveComponents()
the resolvers are called.
My concern is if instead of resolveComponents()
, I call deleteComponents()
, like this:
addComponent();
addComponent();
addComponent();
deleteComponents();
Will that garbage collect the components?
They have unfulfilled promises, the resolvers for these promises are stored in the component.resolvers
.
Since the previous components will be impossible to reach after the deletion, my guess is that they will be collected even though they have unfulfilled promises.
What’s the answer to this?
3
Answers
If there are not references to the promise, and it goes out of scope it will most likely be eligible for GC, although I’m not 100% certain that is the case. It is generally good practice to resolve any promises you have, so I’d suggest calling the resolvers before deleting the components.
You have no circular dependencies, and calling
deleteComponents
lets go of the only reference you have to them. So the components won’t be leakedA
Promise
is just a regular object, so if there are no more references to it, then it gets cleared by the garbage collector (even if in pending state). If aPromise
resolves later, then obviously there is a reference to it somewhere. For example in this code:Even if we don’t store the
Promise
in a variable,setTimeout
keeps a reference to theresolve
function of thePromise
instance during the delay, then thePromise
instance is kept alive until the delay ends.In your example if you replace the components array with an empty one, the components can be garbage collected, along with their
resolvers
property which contains the only references to the Promises, so they can be collected as well.If you have doubts about memory leaks, you can diagnose them easily by taking a snapshot of the memory with the "memory" tab of the browser’s DevTools.