# How JavaScript Promises and Promise.race Resolve: A Deep Dive into Asynchronous Settlement

> Understand how JavaScript Promises and Promise.race resolve asynchronously. Learn about micro-task queues and immediate settlement with Promise.race for efficient async code.

- Repository: [Lydia Hallie/javascript-questions](https://github.com/lydiahallie/javascript-questions)
- Tags: deep-dive
- Published: 2026-03-04

---

**JavaScript Promises settle asynchronously via the micro-task queue, while `Promise.race` returns a new promise that fulfills or rejects immediately when the first promise in the iterable settles, regardless of the outcome.**

Understanding how JavaScript Promises and Promise.race resolve is essential for mastering asynchronous programming in modern JavaScript. The `lydiahallie/javascript-questions` repository provides authoritative explanations of these behaviors in its comprehensive [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) (lines 1380-1392), detailing exactly how promise settlement and racing mechanics work under the hood.

## How JavaScript Promises Resolve Internally

### The Synchronous Executor and Asynchronous Settlement

When you create a promise with `new Promise((resolve, reject) => { … })`, the **executor function** runs immediately and synchronously. However, calls to `resolve(value)` or `reject(reason)` do not execute handlers instantly. Instead, they queue the settlement as a **micro-task**, ensuring that `.then()` and `.catch()` handlers execute only after the current call stack clears.

### The Micro-task Queue and Handler Execution

Once a promise settles, all attached handlers are placed in the **micro-task queue**. These handlers execute before any macro-tasks (such as `setTimeout` callbacks) in the next event loop iteration. This guarantees that promise chains resolve predictably, even when nested within synchronous code blocks.

## How Promise.race Resolves the First Settled Promise

The `Promise.race(iterable)` static method returns a new promise that adopts the state of the **first promise to settle** in the provided iterable. According to the `lydiahallie/javascript-questions` source, this method internally attaches `then` and `catch` handlers to each promise; the first invocation of either handler settles the race promise with that value or reason.

### Settlement Behavior on Resolve vs Reject

`Promise.race` treats **fulfillment and rejection equally**. If the first promise to settle resolves, the race promise resolves with that value. If the first promise rejects, the race promise rejects with that reason. This behavior makes `Promise.race` suitable for implementing timeouts, where a rejection might be the desired "winning" outcome.

### Practical Implementation from the Source

The repository demonstrates this with two competing timers:

```javascript
const firstPromise = new Promise((res) => setTimeout(res, 500, 'one'));
const secondPromise = new Promise((res) => setTimeout(res, 100, 'two'));

Promise.race([firstPromise, secondPromise]).then(res => console.log(res));
// → logs "two"

```

Here, `secondPromise` resolves after **100ms** while `firstPromise` resolves after **500ms**. The race promise fulfills with `'two'` because that promise settled first, as documented in [`README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/README.md) lines 1380-1392.

## Code Examples

**Example 1 – Basic promise resolution**

```javascript
// A simple promise that resolves after 200ms
const p = new Promise((resolve) => setTimeout(() => resolve(42), 200));

p.then(value => console.log('resolved with', value));
// Output (after ~200ms): resolved with 42

```

**Example 2 – Promise.race with mixed resolve/reject**

```javascript
const fastReject = new Promise((_, reject) =>
  setTimeout(() => reject(new Error('boom')), 50)
);
const slowResolve = new Promise((resolve) =>
  setTimeout(() => resolve('ok'), 150)
);

Promise.race([fastReject, slowResolve])
  .then(v => console.log('won:', v))
  .catch(err => console.error('lost:', err.message));
// Output (after ~50ms): lost: boom

```

**Example 3 – Using Promise.race to implement a timeout**

```javascript
function fetchWithTimeout(url, ms) {
  const timeout = new Promise((_, reject) =>
    setTimeout(() => reject(new Error('timeout')), ms)
  );
  const request = fetch(url);
  return Promise.race([request, timeout]);
}

fetchWithTimeout('https://example.com', 3000)
  .then(r => console.log('got response'))
  .catch(e => console.error(e.message));

```

## Summary

- JavaScript promises settle **asynchronously** via the micro-task queue, ensuring handlers execute after the current synchronous code completes.
- The executor function runs **synchronously**, but `resolve` and `reject` queue settlement as micro-tasks.
- `Promise.race` returns a promise that adopts the state of the **first settled promise** in the iterable, whether it fulfills or rejects.
- This racing behavior is implemented by attaching handlers to each promise and settling immediately upon the first invocation, as shown in [`lydiahallie/javascript-questions/README.md`](https://github.com/lydiahallie/javascript-questions/blob/main/lydiahallie/javascript-questions/README.md) (lines 1380-1392).

## Frequently Asked Questions

### Does Promise.race wait for all promises to complete?

No. `Promise.race` settles as soon as the first promise in the iterable settles, regardless of whether other promises are still pending. The remaining promises continue executing in the background, but their eventual results are ignored by the race promise.

### What happens if the first promise in a race rejects?

If the first promise to settle rejects, `Promise.race` returns a rejected promise with that reason. Unlike `Promise.any`, which waits for a fulfillment, `Promise.race` treats rejection as a valid settlement condition and immediately propagates the error to the returned promise.

### How does Promise.race differ from Promise.any?

`Promise.race` settles with the first promise to fulfill **or** reject, while `Promise.any` settles only when the first promise fulfills. If all promises passed to `Promise.any` reject, it returns an `AggregateError`. In contrast, `Promise.race` would have already rejected as soon as the first rejection occurred.

### Can Promise.race be used for request timeouts?

Yes. This is a common pattern where one promise represents the async operation (e.g., a `fetch` request) and another represents a timer that rejects after a specified duration. `Promise.race` between these two promises ensures that if the timer expires first, the race rejects with a timeout error, effectively aborting the wait for the slow request.