Weak references are great, but nearly nothing truly uses it in javascript.
Why not just use WeakMap? A native WeakMap is write only, you cant do things like .forEach
or for (const value of map)
. The only thing it can be used for is seeing if it contains it.
import {WeakRefMap} from "weakrefmap";
class Clients {
constructor(private readonly server: Server) {
}
doSomething() {
}
}
class Server {
clients = new WeakRefMap<string, Client>();
}
function test() {
const server = new Server();
let alice = new Client(server);
const bob = new Client(server);
server.clients.set('alice', alice).add('bob', bob);
server.clients.forEach(client => client.doSomething());
alice = null;
// Alice is still floating in memory
if (server.clients.has('alice')) {
const lostAlice = server.clients.get('alice')
}
}
test();
If this code was written with a normal new Map<string, Client>
, everything would float forever in memory and never be cleaned. As both Client
as Server
have recursive references to each other. The magic of a weak reference will overcome this issue.
In the past, we would have demanded the user to call some server.close()
function, but as we (java|type)script developers are lazy and not used with dealing with the garbage collector, we often forget.
With WeakRefMap the following happen
- End of
test()
, reference all references to the client (clientA
,clientB
) get marked asdeletable
. As the variables are the only ones that count. The weak ref map is not counted as a reference - All
Client
instances get deleted - All server references are gone now, as
test()
'sserver
variable is gone, and so are allClient
objects are gone - All memory usage of
test()
is fully and automatically cleaned up
What happens with a typical Map?
- End of
test()
, references to theclientA
andclientB
are still holden in theServer
instance. - clients instances still exists
- server reference still exists in clients
- all memory of test() is still in memory
- memory leaked