How to Use Promises in JavaScript | The School of Code

Settings

Appearance

Choose a typography theme that suits your style

Back to How-to Guides
JavaScript

How to Use Promises in JavaScript

Learn how to handle asynchronous operations in JavaScript using Promises.

JavaScriptPromisesAsynchronousES6

Promises represent the eventual completion or failure of an asynchronous operation. They’re fundamental to modern JavaScript.

Creating a Promise

const myPromise = new Promise((resolve, reject) => {
    // Async operation
    const success = true;
    
    if (success) {
        resolve("Operation succeeded!");
    } else {
        reject("Operation failed!");
    }
});

Using then() and catch()

myPromise
    .then(result => {
        console.log(result); // "Operation succeeded!"
    })
    .catch(error => {
        console.error(error);
    });

Promise States

A Promise has three states:

  • Pending: Initial state, neither fulfilled nor rejected
  • Fulfilled: Operation completed successfully
  • Rejected: Operation failed
const pending = new Promise(() => {}); // Stays pending
const fulfilled = Promise.resolve("Done");
const rejected = Promise.reject("Error");

Chaining Promises

fetch('/api/user')
    .then(response => response.json())
    .then(user => fetch(`/api/posts/${user.id}`))
    .then(response => response.json())
    .then(posts => {
        console.log(posts);
    })
    .catch(error => {
        console.error("Error:", error);
    });

Returning Values in Chains

Promise.resolve(1)
    .then(value => value + 1)  // Returns 2
    .then(value => value * 2)  // Returns 4
    .then(value => {
        console.log(value);    // 4
    });

Error Handling

catch() Method

fetch('/api/data')
    .then(response => {
        if (!response.ok) {
            throw new Error(`HTTP error: ${response.status}`);
        }
        return response.json();
    })
    .then(data => console.log(data))
    .catch(error => console.error("Caught:", error));

finally() Method

let isLoading = true;

fetch('/api/data')
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error(error))
    .finally(() => {
        isLoading = false;  // Always runs
    });

Promise.all()

Wait for all promises to complete:

const promise1 = fetch('/api/users').then(r => r.json());
const promise2 = fetch('/api/posts').then(r => r.json());
const promise3 = fetch('/api/comments').then(r => r.json());

Promise.all([promise1, promise2, promise3])
    .then(([users, posts, comments]) => {
        console.log(users, posts, comments);
    })
    .catch(error => {
        // Fails fast: rejects if ANY promise rejects
        console.error("One failed:", error);
    });

Promise.allSettled()

Wait for all to settle (fulfill or reject):

const promises = [
    Promise.resolve("Success 1"),
    Promise.reject("Error"),
    Promise.resolve("Success 2")
];

Promise.allSettled(promises)
    .then(results => {
        results.forEach(result => {
            if (result.status === 'fulfilled') {
                console.log("Value:", result.value);
            } else {
                console.log("Reason:", result.reason);
            }
        });
    });
// Value: Success 1
// Reason: Error
// Value: Success 2

Promise.race()

Returns when the first promise settles:

const fast = new Promise(resolve => 
    setTimeout(() => resolve("Fast"), 100)
);
const slow = new Promise(resolve => 
    setTimeout(() => resolve("Slow"), 500)
);

Promise.race([fast, slow])
    .then(result => {
        console.log(result); // "Fast"
    });

Promise.any()

Returns when the first promise fulfills:

const promises = [
    Promise.reject("Error 1"),
    Promise.resolve("Success"),
    Promise.reject("Error 2")
];

Promise.any(promises)
    .then(result => {
        console.log(result); // "Success"
    })
    .catch(errors => {
        // Only if ALL reject
        console.log(errors);
    });

Creating Utility Functions

Delay Function

function delay(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

// Usage
delay(2000).then(() => console.log("2 seconds passed"));

Timeout Wrapper

function withTimeout(promise, ms) {
    const timeout = new Promise((_, reject) => 
        setTimeout(() => reject(new Error("Timeout")), ms)
    );
    return Promise.race([promise, timeout]);
}

// Usage
withTimeout(fetch('/api/data'), 5000)
    .then(response => response.json())
    .catch(error => console.error(error));

Retry Logic

function retry(fn, retries = 3, delay = 1000) {
    return fn().catch(error => {
        if (retries > 0) {
            return new Promise(resolve => 
                setTimeout(resolve, delay)
            ).then(() => retry(fn, retries - 1, delay));
        }
        throw error;
    });
}

// Usage
retry(() => fetch('/api/data'), 3)
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(error => console.error("All retries failed"));

Converting Callbacks to Promises

// Callback-based function
function readFileCallback(path, callback) {
    // callback(error, data)
}

// Promisified version
function readFilePromise(path) {
    return new Promise((resolve, reject) => {
        readFileCallback(path, (error, data) => {
            if (error) {
                reject(error);
            } else {
                resolve(data);
            }
        });
    });
}

// Usage
readFilePromise('/path/to/file')
    .then(data => console.log(data))
    .catch(error => console.error(error));

Summary

  • Create with new Promise((resolve, reject) => {})
  • Handle success with .then()
  • Handle errors with .catch()
  • Clean up with .finally()
  • Promise.all() - wait for all, fail fast
  • Promise.allSettled() - wait for all to settle
  • Promise.race() - first to settle wins
  • Promise.any() - first to fulfill wins