When a promise settles, then lets you register a fulfillment callback and a rejection callback. It’s also the link that turns separate asynchronous steps into a readable sequence. section 6.3
Listing 6.10. Creating a simple promise
const ninjaPromise = new Promise((resolve, reject) => { #A
resolve("Hattori"); #B
//reject("An error resolving a promise!"); #B
});
ninjaPromise.then(ninja => { #C
assert(ninja === "Hattori", "We were promised Hattori!"); #C
}, err => { #D
fail("There shouldn't be an error") #D
}); #D
See a promise resolved with a value and the two callbacks passed to then. section 6.3
Each call to then returns a new promise, so another then can handle the next result. For dependent requests, this avoids nesting callbacks. A rejection callback can handle an error at one step; a catch at the end can handle failures across the chain. section 6.3.5
Listing 6.16. Chaining promises with then
getJSON("data/ninjas.json")
.then(ninjas => getJSON(ninjas[0].missionsUrl)) #A
.then(missions => getJSON(missions[0].detailsUrl)) #A
.then(mission => assert(mission !== null, "Ninja mission obtained!")) #A
.catch(error => fail("An error has occurred")); #B
Follow a chain that fetches ninja data, missions, and mission details, then handles failure with catch. section 6.3.5




