A Promise is a JavaScript object representing the eventual completion or failure of an asynchronous operation. Introduced in ES6 (2015), Promises replaced callback-heavy code with a cleaner chaining syntax, and they’re the foundation of async/await.
Problem: How do you handle asynchronous JavaScript operations — API calls, timers, or file reads — without falling into deeply nested callback functions?
Solution: Use Promises to represent the eventual result of an async operation. Chain .then() for success and .catch() for errors; use Promise.all() to run multiple operations in parallel and wait for all of them to resolve.
// Creating a Promise
const wait = ( ms ) => new Promise( ( resolve, reject ) => {
if ( ms < 0 ) {
reject( new Error( 'Wait time cannot be negative' ) );
return;
}
setTimeout( resolve, ms );
} );
// Consuming a Promise — .then() / .catch() / .finally()
wait( 1000 )
.then( () => console.log( 'Done after 1 second' ) )
.catch( err => console.error( err.message ) )
.finally( () => console.log( 'Always runs' ) );
Chaining — each .then() receives the return value of the previous one:
fetch( '/wp-json/wp/v2/posts?per_page=5' )
.then( response => {
if ( ! response.ok ) throw new Error( `HTTP error: ${response.status}` );
return response.json(); // returns another Promise
} )
.then( posts => posts.map( p => p.title.rendered ) )
.then( titles => console.log( titles ) )
.catch( err => console.error( 'Fetch failed:', err ) );
Static Promise methods:
// Promise.all — wait for all, fail fast if any rejects
Promise.all( [
fetch( '/wp-json/wp/v2/posts' ).then( r => r.json() ),
fetch( '/wp-json/wp/v2/categories' ).then( r => r.json() ),
] ).then( ( [ posts, cats ] ) => {
console.log( posts.length, cats.length );
} );
// Promise.allSettled — wait for all, never rejects (ES2020 but safe to use in 2019 with a polyfill)
// Promise.race — resolves/rejects as soon as the first Promise settles
Promise.race( [
fetch( '/wp-json/wp/v2/posts' ),
new Promise( ( _, reject ) => setTimeout( () => reject( new Error( 'Timeout' ) ), 5000 ) ),
] ).then( res => res.json() )
.catch( err => console.error( err.message ) );
NOTE: Always attach a .catch() handler to every Promise chain — unhandled rejections crash the Node.js process (in newer versions) and produce console warnings in browsers. If you forget .catch(), use the global unhandledrejection event as a safety net: window.addEventListener('unhandledrejection', e => console.error(e.reason)).