Combining Promises

Then provides several powerful utilities for working with multiple promises at once.

whenAll

Promises.whenAll is used when you have multiple asynchronous operations and you need to wait for all of them to complete successfully before proceeding. It takes an array of promises (or a variadic list) and returns a new promise.

  • This new promise fulfills with an array containing the results of all the input promises, in their original order.
  • If any of the input promises reject, the whenAll promise immediately rejects with that same error.
let promiseA = fetchUsersA() // -> Promise<[User]>
let promiseB = fetchUsersB() // -> Promise<[User]>
let promiseC = fetchUsersC() // -> Promise<[User]>

Promises.whenAll(promiseA, promiseB, promiseC).then { allUsersArray in
  // allUsersArray is a single array: [[User], [User], [User]]
  // Let's flatten it
  let allUsers = allUsersArray.flatMap { $0 }
  print("Fetched a total of \(allUsers.count) users.")
}.onError { error in
  print("One of the fetch operations failed: \(error)")
}

whenAll also works with promises that return arrays themselves (Promise<[T]>), and it will flatten the results into a single array [T].

race

Promises.race takes multiple promises and returns a new promise that resolves or rejects as soon as the first of the input promises resolves or rejects. It's a race to the finish.

This is useful when you have multiple sources for the same data (e.g., a cache and a network request) and you want to use whichever one returns first.

let fetchFromCache = fetchResourceFromCache() // -> Promise<Data>
let fetchFromNetwork = fetchResourceFromNetwork() // -> Promise<Data>

Promises.race(fetchFromCache, fetchFromNetwork).then { data in
  // This block is executed with the data from whichever promise finished first.
  print("Got the resource!")
}

zip

Promises.zip is used when you need to combine the results of multiple promises that have different types. It waits for all promises to complete successfully and then fulfills with a tuple containing all the results.

Like whenAll, if any of the input promises fail, the zip promise also fails.

let userPromise = fetchUser()       // -> Promise<User>
let settingsPromise = fetchSettings() // -> Promise<Settings>

Promises.zip(userPromise, settingsPromise).then { (user, settings) in
  // Both promises have completed successfully
  print("Welcome, \(user.name). Your theme is \(settings.theme).")
}

Then provides overloads for zip to combine up to 8 promises.