first step is to think about the data structure. The most straightforward choice is to use Map, because we need to use a <K,V> for storage
here terminal will output with:
now, the first issue comes, when we use Map<event,Function> as the data structure then we will face how to trigger the same event with different callback function… problems like below.
the second log will overlap the first one,because if there is existed key in Map, then set() will update with the value and overlap the previous valu. so Map<K,V>should use -> Map<string, Function[]> instead of Map<string, Function>
console.log("*".repeat(40), "version 3"); classEventEmitterV4 { privateeventRegister: Map<string, { fn: Function, onceFlag: boolean }[]>;//we need to update the structure constructor() { this.eventRegister = newMap(); }
on(event: string, fn: Function, onceFlag: boolean = false) { const fnList = this.eventRegister.get(event); if (fnList) fnList.push({ fn, onceFlag }); // need to baesed on the structure elsethis.eventRegister.set(event, [{ fn, onceFlag }]);// need to baesed on the structure }
once(event: string, fn: Function, onceFlag: boolean = false) { const fnList = this.eventRegister.get(event); if (fnList) fnList.push({ fn, onceFlag });// need to baesed on the structure elsethis.eventRegister.set(event, [{ fn, onceFlag }]);// need to baesed on the structure }
emit(event: string, info: string) {... }
off(event: string, fn: Function) {... }
}
This approach is intuitive and easy to understand, but it doesn’t feel elegant. As developers, we value elegance, so let’s use a neat trick to implement it. Here’s where the magic comes in:
off(event: string, fn: Function) { if (!this.eventRegister.get(event)) return; const fnList = this.eventRegister.get(event)?.filter(f => f !== fn); this.eventRegister.set(event, fnList!); }
once(event: string, fn: Function) { //nothing changed above, just to use a wrapper to implement this feature. constwrapper = (args) => { this.off(event, wrapper); fn(args); } this.on(event, wrapper);%t
// For newcomers to TypeScript, this might feel a bit hard to understand, but think of it this way: 1.this. on(event,fn()); // this is what we want, but we need to invoke the off() after fn() // then we create a wrapper to do it, and set the wrapper to this.on(..) } }
If not found, the system checks the operating system’s DNS cache and the hosts file.
If still not found, the request is sent to the configured recursive resolver
The recursive resolver performs the lookup step by step: • It asks a root server, which points to the relevant top-level domain (TLD) server (e.g., .com). • Then it queries the TLD server, which points to the authoritative server for the domain (e.g., example.com). • Finally, it queries the authoritative DNS server, which provides the actual IP address.
The IP address is returned to the client, and Chrome uses it to establish the connection.
TCP handshake
Client side will send api with [SYNC = 1], Seq = i,
Server side will return api with [SYNC = 1, ACK = 1] , Ack = i+1, Seq = u
Client side will send api with [ACK = 1], Ack = u+1
TLS Connection
HTTP / HTTPS
TCP disconnection
Client send [FIN = 1, ACK = 1], seq = u,
Server side send [ ACK = 1], Seq = j, Ack = u+1
Server side send [FIN = 1, ACK = 1], Seq = j, Ack = u+1