Promises and Asynchrony

JavaScript runs your code on one thread, so for network requests, timers and clicks you hand the runtime a callback to call later. Sequential callbacks nest into a "pyramid of doom". A promise is an object standing for a result that is not ready yet; then() and catch() return new promises, so the steps form a flat chain.

Three asynchronous steps as nested callbacks and as a promise chainJavaScriptLive
const later = (n, cb) => setTimeout(() => cb(null, n + 1), 10);   // Node style: cb(err, result)
later(1, (err, a) => later(a, (err, b) => later(b, (err, c) =>    // each step nests deeper
  console.log("callbacks:", c))));
const laterP = n => new Promise(resolve => setTimeout(resolve, 10, n + 1));
laterP(1).then(laterP).then(laterP).then(c => console.log("promises:", c)).catch(console.error);

A promise starts pending and settles once, as fulfilled with a value or rejected with a reason. "Resolved" is not a synonym for fulfilled: a resolved promise is locked in to follow another one and may still be pending. Promises follow the Promises/A+ (https://promisesaplus.com/ 424,259 ) specification and joined the language in ECMAScript 2015; async/await followed in ECMAScript 2017.

The life cycle of a promise: it settles once and never changes again
The life cycle of a promise: it settles once and never changes again

Subsections