The caching mechanism in asyncPuzzle fails under concurrent requests. Why?
const asyncPuzzle = {
cache: new Map(),
async getData(key) {
if (this.cache.has(key)) return this.cache.get(key);
const result = await fetch(`/api/${key}`);
this.cache.set(key, result);
return result;
},
async challenge() {
const results = await Promise.all([
this.getData('x'),
this.getData('x'),
this.getData('x')
]);
}
};
Challenge: Fix the implementation to ensure only one API call is made regardless of concurrent requests.
The race condition occurs because the cache check and set aren't atomic operations.
// Fixed implementation
const asyncPuzzle = {
cache: new Map(),
pendingRequests: new Map(),
async getData(key) {
if (this.cache.has(key)) return this.cache.get(key);
if (this.pendingRequests.has(key)) {
return this.pendingRequests.get(key);
}
const promise = fetch(`/api/${key}`);
this.pendingRequests.set(key, promise);
try {
const result = await promise;
this.cache.set(key, result);
return result;
} finally {
this.pendingRequests.delete(key);
}
}
};
class EventManager {
constructor() {
this.handlers = new WeakMap();
this.element = document.getElementById('memory-test');
}
attach() {
const handler = () => {
this.handlers.set(this, {
data: new Array(1000000).fill('test'),
cleanup: () => this.detach()
});
};
this.element.addEventListener('click', handler);
}
detach() {
this.handlers.delete(this);
}
}
The EventManager class has a subtle memory leak. Find and fix it.
The memory leak occurs due to improper event listener cleanup and WeakMap usage.
class EventManager {
constructor() {
this.handlers = new WeakMap();
this.element = document.getElementById('memory-test');
}
attach() {
const handler = () => {
console.log('handled');
};
this.element.addEventListener('click', handler);
// Store handler reference for cleanup
this.handlers.set(this.element, handler);
}
detach() {
const handler = this.handlers.get(this.element);
if (handler) {
this.element.removeEventListener('click', handler);
this.handlers.delete(this.element);
}
}
}
const target = {
name: 'test',
_private: 'secret'
};
const handler = {
get(target, prop) {
if (prop.startsWith('_')) return undefined;
return target[prop];
},
set(target, prop, value) {
if (prop.startsWith('_')) return false;
target[prop] = value;
return true;
},
deleteProperty(target, prop) {
if (prop.startsWith('_')) return false;
return delete target[prop];
}
};
const proxy = new Proxy(target, handler);
Challenge: Bypass the Proxy protection to access and modify private properties.
Several ways to bypass the Proxy protection:
// Method 1: Using Object.getOwnPropertyDescriptor
const value = Object.getOwnPropertyDescriptor(target, '_private').value;
// Method 2: Using Reflect
const value = Reflect.get(target, '_private');
// Method 3: Getting the target through proxy's constructor
const originalTarget = proxy.constructor.prototype.constructor.target;
const value = originalTarget._private;
function* infiniteGenerator() {
let current = 0;
while (true) {
const reset = yield current++;
if (reset) current = 0;
}
}
async function* asyncWrapper(generator) {
const gen = generator();
while (true) {
const next = gen.next();
yield await next;
}
}
The asyncWrapper function causes a deadlock when used with infiniteGenerator. Why?
Challenge: Fix the implementation to properly handle both sync and async generators.
The deadlock occurs because we're awaiting a non-Promise value.
async function* fixedAsyncWrapper(generator) {
const gen = generator();
while (true) {
const next = gen.next();
// Only await if it's actually a Promise
yield next instanceof Promise ? await next : next.value;
}
}
// Usage example:
const gen = fixedAsyncWrapper(infiniteGenerator);
for await (const value of gen) {
console.log(value); // Works correctly now
if (value > 10) break;
}
class Base {
constructor() {
this.value = 42;
}
getValue() {
return this.value;
}
}
class Derived extends Base {
constructor() {
super();
Object.setPrototypeOf(this, {
getValue: function() {
return this.value * 2;
}
});
}
}
What are the implications of mutating the prototype chain in the constructor?
Challenge: Predict and explain the behavior of instanceof and inheritance.
Prototype chain mutation causes several issues:
// Correct way to modify behavior while maintaining prototype chain
class Base {
constructor() {
this.value = 42;
}
getValue() {
return this.value;
}
}
class Derived extends Base {
getValue() {
// Properly override method while maintaining inheritance
return super.getValue() * 2;
}
}
// Test:
const derived = new Derived();
console.log(derived instanceof Derived); // true
console.log(derived instanceof Base); // true
console.log(derived.getValue()); // 84