Top 5 JS Challenges

JavaScript interviews in 2025 are no longer about simple tricks. Companies test how well you understand async control, data structures, and system-like patterns.

Here are 5 high-frequency coding challenges you're likely to face this year, along with clean solutions.

1. Custom Promise.all

Implement a custom Promise.all that resolves when all promises succeed, or rejects on the first failure.

function promiseAll(promises) {
  return new Promise((resolve, reject) => {
    let results = [];
    let completed = 0;
    promises.forEach((p, i) => {
      Promise.resolve(p)
        .then((val) => {
          results[i] = val;
          completed++;
          if (completed === promises.length) resolve(results);
        })
        .catch(reject);
    });
  });
}

// Example:
promiseAll([Promise.resolve(1), Promise.resolve(2)]).then(console.log); // [1, 2]

2. Retry with Exponential Backoff

Retry an async task with exponential delay between attempts.

async function retryWithBackoff(fn, retries, delay) {
  let attempt = 0;
  while (attempt < retries) {
    try {
      return await fn();
    } catch (err) {
      attempt++;
      if (attempt >= retries) throw err;
      await new Promise((res) =>
        setTimeout(res, delay * 2 ** attempt)
      );
    }
  }
}

3. Curry Implementation

Implement a curry function that allows partial application.

function curry(fn) {
  return function curried(...args) {
    if (args.length >= fn.length) {
      return fn.apply(this, args);
    } else {
      return (...next) => curried.apply(this, args.concat(next));
    }
  };
}

// Example:
function add(a, b, c) {
  return a + b + c;
}
const curriedAdd = curry(add);

console.log(curriedAdd(1)(2)(3)); // 6

4. LRU Cache

Design a Least Recently Used cache with O(1) get and put.

class LRUCache {
  constructor(capacity) {
    this.capacity = capacity;
    this.map = new Map();
  }
  get(key) {
    if (!this.map.has(key)) return -1;
    const val = this.map.get(key);
    this.map.delete(key);
    this.map.set(key, val);
    return val;
  }
  put(key, val) {
    if (this.map.has(key)) this.map.delete(key);
    if (this.map.size >= this.capacity) {
      this.map.delete(this.map.keys().next().value);
    }
    this.map.set(key, val);
  }
}

5. Event Emitter

Implement a minimal event emitter with on, emit, and off.

class EventEmitter {
  constructor() {
    this.events = {};
  }
  on(event, cb) {
    (this.events[event] = this.events[event] || []).push(cb);
  }
  emit(event, ...args) {
    (this.events[event] || []).forEach((cb) => cb(...args));
  }
  off(event, cb) {
    this.events[event] = (this.events[event] || []).filter(
      (fn) => fn !== cb
    );
  }
}

Wrapping Up

If you're interviewing for frontend or fullstack roles in 2025, expect questions like these.

They test your ability to handle async control flow, caching, and functional programming, things you'll build in real-world apps too.

Practice solving them under time pressure, and always be ready to explain your reasoning. That's what separates average candidates from top hires.