Back to list
ReactPromiseAPIJavaScriptasync

[React][API] The Promise You See on Every API Call

Why fetch returns Promise { <pending> }, the three Promise states, and how .then / .catch / .finally map to real API success and failure - plus how async/await sits on top.

1. Environment

  • OS: Windows 11 / macOS
  • Language: JavaScript (ES6+)
  • Frontend library: React.js
  • IDE: Visual Studio Code (VS Code)

2. Problem

If you have called a server API from JavaScript or React, you have probably seen this odd console value: Promise { <pending> }.

Earlier posts cover async / await for browser async work. The backbone of that syntax - and the real star of JavaScript async - is the Promise.

3. Cause

JavaScript does not patiently freeze until the server answers.

Instead it hands you a “I will notify you when the data arrives|–voucher and continues with the next lines. That voucher is a Promise.

// Common mistake
const userData = fetch('https://api.example.com/user');
console.log(userData);

// Expected: { name: "Hong Gildong", age: 20 }
// Actual:   Promise { <pending> }

4. Solution

1) Promise as a vibrating pager

Think of a Promise as a future result ticket for work that is not finished yet.

  1. Order (API call): The client orders an Americano.
  2. Promise issued: The server gives a vibrating pager (Promise), not the coffee yet - so the client can do other work.
  3. Fulfilled: The pager buzzes; you get the coffee (data).
  4. Rejected: The machine fails; you get a refund (error message).

2) Three Promise states

State Meaning
Pending Waiting with the pager - work not finished
Fulfilled Success - data arrived
Rejected Failure - error occurred

3) Controlling a Promise (.then / .catch / .finally)

fetch() is a classic function that returns a Promise (the pager):

fetch('https://api.example.com/user')
  // 1. Success (Fulfilled): .then()
  .then((response) => {
    console.log('Request succeeded!');
    return response.json(); // pass parsed data to the next then
  })
  .then((data) => {
    console.log('User data:', data);
  })
  // 2. Failure (Rejected): .catch()
  // 404, offline drop, etc.
  .catch((error) => {
    console.error('Server problem!', error);
  })
  // 3. Always runs: .finally()
  // Great for turning off a loading spinner
  .finally(() => {
    console.log('Request finished. Clear loading state.');
  });

5. Summary

A Promise during server I/O is JavaScript?’s note: “Data is coming - wait a moment.|–

You mainly decide what to do when the pager succeeds (.then) or fails (.catch).

If chaining .then().catch() feels noisy, async / await is the newer style that reads as “stand here until the pager buzzes” - built on the same Promise foundation.

Related posts