FrontendAtlas
Interview Questions
Home>JavaScript interview questions> JavaScript coding challenges >Implement createDeferred() in JavaScript

Implement createDeferred() in JavaScript

intermediate
By FrontendAtlas Editorial · Updated Jul 14, 2026
Implement createDeferred() in JavaScript. Your function should return { promise, resolve, reject } so async tests can control exactly when a Promise fulfills or rejects. The challenge includes starter code, tests for resolve/reject behavior, promise adoption, pending state, first-settlement-wins edge cases, and interview follow-ups.

What you'll practice:

  • Creating createDeferred() with { promise, resolve, reject } controls
  • Making async tests deterministic without real timers
  • Handling resolve(value), reject(error), Promise adoption, pending state, and first-settlement-wins behavior

Expected behavior

Your createDeferred() implementation should:

  • Return { promise, resolve, reject }
  • Fulfill the promise when resolve(value) is called
  • Reject the promise with the exact reason when reject(error) is called
  • Adopt another Promise when resolve(Promise.resolve(value)) is used
  • Remain pending until resolve or reject is called
  • Use normal Promise semantics so only the first settlement wins and callbacks run in a later microtask

Returns

{ promise: Promise, resolve: Function, reject: Function } — The createDeferred() controls object: a Promise plus resolve(value) and reject(error) functions for settling it later.
Examples
// Example: timeline
// At t=0
const d = createDeferred();
const result = d.promise.then((value) => `loaded:${value}`);

// At t=50
// d.promise is still pending because neither resolve nor reject has been called.

// At t=100
d.resolve('user');

// After the next microtask
await result; // 'loaded:user'

// Promise adoption
const adopted = createDeferred();
adopted.resolve(Promise.resolve('ok'));
await adopted.promise; // 'ok'

Solution

Overview

Interview answer: the base prompt is to create one Promise and capture its resolve and reject functions from the Promise constructor. Return those controls with the promise so tests can decide when async work finishes. TypeScript typing, timeout safeguards, cancellation, and production-safety concerns are follow-ups, not part of the minimal createDeferred() contract.

Mental model: createDeferred() returns { promise, resolve, reject }. Calling resolve(value) fulfills the promise, calling reject(error) rejects it, and resolving with another Promise adopts that Promise's eventual state. Normal Promise semantics also keep callbacks asynchronous and make the first settlement win.

1

Approach: Capture resolve/reject from one Promise

Steps:

1) Declare resolve and reject variables in the outer function scope.

2) Create one Promise with new Promise((res, rej) => { resolve = res; reject = rej; }).

3) Return { promise, resolve, reject }.

Do not add timers, AbortController, retries, event emitters, cancellation APIs, or a custom Promise implementation for the base challenge. Native Promise behavior already handles promise adoption, asynchronous callbacks, and first-settlement-wins semantics.

Complexity: O(1) time, O(1) space.

export default function createDeferred() {
  let resolve;
  let reject;

  const promise = new Promise((res, rej) => {
    resolve = res;
    reject = rej;
  });

  return { promise, resolve, reject };
}
export type Deferred<T> = {
  promise: Promise<T>;
  resolve: (value: T | PromiseLike<T>) => void;
  reject: (reason?: any) => void;
};

export default function createDeferred<T = unknown>(): Deferred<T> {
  let resolve!: (value: T | PromiseLike<T>) => void;
  let reject!: (reason?: any) => void;

  const promise = new Promise<T>((res, rej) => {
    resolve = res;
    reject = rej;
  });

  return { promise, resolve, reject };
}

Notes & Pitfalls

Pitfalls
  • Do not create a new Promise inside resolve or reject; create one Promise and expose its captured controls.
  • Do not wrap resolve values manually; native Promise resolution already adopts PromiseLike values.
  • Do not add timeout, cancellation, retry, or event-emitter behavior to the minimal createDeferred() contract.
Edge cases
  • The promise stays pending until resolve or reject is called.
  • Only the first resolve/reject call wins; later settlement attempts are ignored by Promise semantics.
  • then/catch/finally callbacks run asynchronously in a later microtask, not in the same call stack as resolve.
Techniques
  • Capture resolve and reject from the Promise constructor.
  • Return { promise, resolve, reject } so tests can settle async work deterministically.
  • Rely on native Promise adoption when resolve receives another PromiseLike.

Common interview follow-ups:

  • How would you type { promise, resolve, reject } in TypeScript?
  • When is createDeferred() useful in async tests?
  • How would you add timeout safeguards without changing the minimal createDeferred() contract?
  • Why can deferred promise controls be risky in production code?

Resources

  • MDN – Promise constructor

Related links

Implement debounce() in JavaScriptCodingImplement takeLatest in JavaScriptCodingFix stale UI from async race conditionsJavaScriptReact debounced search coding challengeReactJavaScript coding interview questionsGuide

Guides

Frontend interview preparation guideGuideFrontend coding interview questions and prep guideBlueprintJavaScript Problems That Actually Show UpBlueprintBuild Great UI in 60 MinutesBlueprint

Preparing for interviews? Use Frontend Coding Challenges first, then move into a concrete Study Plan before targeted Company Prep.

Open frontend interview questionsBrowse JavaScript interview questionsOpen Essential 60Open Machine Coding HubOpen Frontend Coding ChallengesOpen System DesignOpen Interview Prep GuideOpen System Design BlueprintOpen Framework Prep PathsOpen Study PlansOpen JavaScript mastery study planOpen Company PrepOpen JavaScript Framework Prep Guide
↗Incidents hub
2 / 88Next →→