Quick Start

This guide will walk you through creating and using your first Promise. Let's build a simple asynchronous chain to fetch a user ID.

1. Create a Promise-Returning Function

A Promise wraps an asynchronous operation. To create one, you initialize a Promise and use the provided resolve and reject closures to signal success or failure.

Let's create a function that simulates a network request to get a user ID.

import Then

func fetchUserId() -> Promise<Int> {
    return Promise { resolve, reject in
        print("Fetching user ID...")

        // Simulate a delay for the network request
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            // On success, call resolve with the result
            resolve(1234)
        }
    }
}

In this function:

  • It returns a Promise<Int>, indicating it will eventually produce an integer or an error.
  • The resolve closure is called with the value (1234) when the operation is successful.
  • The reject closure (which we're not using here) would be called with an Error if something went wrong.

2. Consume the Promise

Now that you have a function that returns a Promise, you can use it. The .then() method is called when the promise resolves successfully.

fetchUserId().then { id in
    print("Successfully fetched UserID: \(id)")
}

// Console output after ~1 second:
// Fetching user ID...
// Successfully fetched UserID: 1234

3. Handle Errors

What if the network request fails? Let's create a version of our function that can fail.

enum APIError: Error {
    case networkFailed
}

func failingFetchUserId() -> Promise<Int> {
    return Promise { resolve, reject in
        print("Fetching user ID...")
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            // On failure, call reject with an error
            reject(APIError.networkFailed)
        }
    }
}

You can catch errors from any point in the promise chain using the .onError() method.

failingFetchUserId().then { id in
    // This block will not be executed
    print("Successfully fetched UserID: \(id)")
}.onError { error in
    print("An error occurred: \(error)")
}

// Console output after ~1 second:
// Fetching user ID...
// An error occurred: networkFailed

4. Perform Cleanup

The .finally() method allows you to execute a block of code regardless of whether the promise succeeded or failed. This is perfect for cleanup tasks, like hiding a loading indicator.

fetchUserId().then { id in
    print("UserID: \(id)")
}.onError { error in
    print("Error: \(error)")
}.finally {
    print("Operation complete.")
}

// Console output:
// Fetching user ID...
// UserID: 1234
// Operation complete.

You have now created and consumed your first promise chain! To learn more, explore how to Create Promises in more detail and how to perform Promise Chaining.