JavaScript Interview Guide Part 4: Advanced Patterns and Performance Optimization
- //continuation from part 3
28. Promise.race Implementation
Interviewer: "Can you implement your own version of Promise.race?"
Candidate: "Here's an implementation that mirrors the native Promise.race behavior:
function promiseRace(promises) {
return new Promise((resolve, reject) => {
promises.forEach(promise => {
Promise.resolve(promise).then(resolve).catch(reject);
});
});
}
// Example usage
const promises = [
new Promise(resolve => setTimeout(() => resolve('First'), 500)),
new Promise(resolve => setTimeout(() => resolve('Second'), 200)),
new Promise((_, reject) => setTimeout(() => reject('Error'), 300))
];
promiseRace(promises)
.then(console.log)
.catch(console.error);
The key point here is that it resolves or rejects with the first promise that settles, just like the native implementation."
29. Promise.any Implementation
Interviewer: "How would you implement Promise.any?"
Candidate: "Here's how I'd implement Promise.any which resolves with the first successful promise:
function promiseAny(promises) {
return new Promise((resolve, reject) => {
let errors = [];
let pending = promises.length;
if (pending === 0) {
reject(new AggregateError([], 'No promises to resolve'));
return;
}
promises.forEach((promise, index) => {
Promise.resolve(promise)
.then(resolve)
.catch(error => {
errors[index] = error;
pending--;
if (pending === 0) {
reject(new AggregateError(errors));
}
});
});
});
}
// Usage
const promises = [
Promise.reject('Error 1'),
Promise.resolve('Success'),
Promise.reject('Error 2')
];
promiseAny(promises).then(console.log);
Unlike Promise.race, this waits for the first success rather than the first settlement."
30. Promise.allSettled Implementation
Interviewer: "Can you implement Promise.allSettled?"
Candidate: "Here's an implementation that handles both fulfilled and rejected promises:
function promiseAllSettled(promises) {
return Promise.all(
promises.map(promise =>
Promise.resolve(promise)
.then(value => ({
status: 'fulfilled',
value
}))
.catch(reason => ({
status: 'rejected',
reason
}))
)
);
}
// Example usage
const promises = [
Promise.resolve(1),
Promise.reject('error'),
Promise.resolve(3)
];
promiseAllSettled(promises).then(results => {
results.forEach(result => {
if (result.status === 'fulfilled') {
console.log('Success:', result.value);
} else {
console.log('Error:', result.reason);
}
});
});
This gives us the status of all promises regardless of whether they succeeded or failed."
31. Clear All Timeouts
Interviewer: "How would you implement a function to clear all existing timeouts?"
Candidate: "Here's a solution that tracks and clears all timeouts:
const timeoutIds = new Set();
// Override setTimeout
const originalSetTimeout = window.setTimeout;
window.setTimeout = function(callback, delay, ...args) {
const id = originalSetTimeout(callback, delay, ...args);
timeoutIds.add(id);
return id;
};
function clearAllTimeouts() {
timeoutIds.forEach(id => {
clearTimeout(id);
timeoutIds.delete(id);
});
}
// Usage
setTimeout(() => console.log('1'), 1000);
setTimeout(() => console.log('2'), 2000);
clearAllTimeouts(); // Clears all pending timeouts
This is useful for cleanup in SPA applications or when transitioning between different states."
32. Memoization Implementation
Interviewer: "Can you implement a memoization function with cache size limit?"
Candidate: "I'll implement a memoize function with LRU cache:
function memoize(fn, { maxSize = 100 } = {}) {
const cache = new Map();
return function(...args) {
const key = JSON.stringify(args);
if (cache.has(key)) {
// Move to most recently used
const value = cache.get(key);
cache.delete(key);
cache.set(key, value);
return value;
}
const result = fn.apply(this, args);
if (cache.size >= maxSize) {
// Remove least recently used
const firstKey = cache.keys().next().value;
cache.delete(firstKey);
}
cache.set(key, result);
return result;
};
}
// Usage
const expensiveOperation = memoize(
(n) => {
console.log('Computing...');
return n * 2;
},
{ maxSize: 2 }
);
This implementation provides both caching and memory management."
33. Async Progress Bar
Interviewer: "How would you implement an async progress bar for multiple operations?"
Candidate: "Here's a simple implementation that tracks multiple async operations:
class ProgressTracker {
constructor(total) {
this.total = total;
this.completed = 0;
this.listeners = new Set();
}
onProgress(callback) {
this.listeners.add(callback);
return () => this.listeners.delete(callback);
}
increment() {
this.completed++;
const progress = (this.completed / this.total) * 100;
this.listeners.forEach(cb => cb(progress));
}
}
// Usage
async function uploadFiles(files) {
const tracker = new ProgressTracker(files.length);
tracker.onProgress(progress => {
console.log(`Upload progress: ${progress}%`);
});
await Promise.all(files.map(async file => {
await uploadFile(file);
tracker.increment();
}));
}
This provides a reusable way to track progress across multiple async operations."
34. GroupBy Polyfill
Interviewer: "Can you implement a polyfill for Array.prototype.groupBy?"
Candidate: "Here's a polyfill that matches the TC39 proposal:
if (!Array.prototype.groupBy) {
Array.prototype.groupBy = function(keyFn) {
return this.reduce((groups, item) => {
const key = keyFn(item);
if (!groups[key]) {
groups[key] = [];
}
groups[key].push(item);
return groups;
}, {});
};
}
// Usage example
const inventory = [
{ name: 'apple', type: 'fruit' },
{ name: 'carrot', type: 'vegetable' },
{ name: 'banana', type: 'fruit' }
];
const grouped = inventory.groupBy(item => item.type);
/* Result:
{
fruit: [
{ name: 'apple', type: 'fruit' },
{ name: 'banana', type: 'fruit' }
],
vegetable: [
{ name: 'carrot', type: 'vegetable' }
]
}
*/
This implementation follows the proposed standard while maintaining compatibility."
Key Interview Tips for Part 4:
Focus on explaining performance implications
Be ready to discuss browser compatibility
Mention error handling and edge cases
Consider memory management
Be prepared to discuss real-world applications
This completes our four-part JavaScript interview preparation series. Good luck with your interviews! ๐