Nested.then(..) with multiple dependent Promises

This situation is what most people get hung up on with Promises. In this example, let’s say we have 4 Promises: connectDatabase(), findAllBooks(database), getCurrentUser(database), and pickTopRecommendation(books, user). The naïve code is:

connectDatabase()

.then((database) => {

return findAllBooks(database)

.then((books) => {

return getCurrentUser(database)

.then((user) => {

return pickTopRecommendation(books, user);

});

});

});

Naïvely we will think this is the best we can do. How else can we get a reference to books and user at the same time? This code also has other issues, such as when we call getCurrentUser(database), we have books unnecessarily in scope. The solution is to understand Promises can be held in a reference. We can extract the common bits out.

const databasePromise = connectDatabase(); const booksPromise = databasePromise

.then(findAllBooks); const userPromise = databasePromise

.then(getCurrentUser); Promise.all([

booksPromise,

userPromise

])

.then((values) => {

const books = values[0];

const user = values[1];

return pickTopRecommentations(books, user);

});

But wait, doesn’t this mean we connect to the database twice? We call .then(..) on databasePromise twice! This is a key thing to understand about Promises, they are only ever resolved once per creation. This means you can call .then(..) as many times as you want, and you’ll only ever get one database connection. This is not the case if you call connectDatabase() multiple times.

The extraction of the values out of promises is a bit ugly. It can be simplifed using with destructuring with Node.js 6.x or greater.

Promise.all([

booksPromise,

userPromise

])

.then(([books, user]) => pickTopRecommentations(books, user));

Alternatively it can be simplified with Ramda’s apply.