Handling Progress

For long-running asynchronous tasks like file uploads or downloads, providing progress updates to the user is essential. Then has built-in support for reporting and handling progress.

Reporting Progress

To enable progress reporting, you use the Promise initializer that includes a progress closure. This closure can be called as many times as needed to report the current progress as a Float value between 0.0 and 1.0.

Here is an example of a function that simulates a file upload and reports its progress.

func uploadAvatar(_ image: UIImage) -> Promise<URL> {
    return Promise { resolve, reject, progress in
        print("Starting upload...")

        // Simulate progress updates
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            progress(0.25)
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
            progress(0.5)
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 1.5) {
            progress(0.75)
        }

        // Simulate completion
        DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
            let url = URL(string: "https://example.com/avatar.png")!
            resolve(url)
        }
    }
}

Consuming Progress Updates

To listen for progress updates, you can chain the .progress() method onto your promise. The block you provide will be called every time the promise reports a new progress value.

The .progress() method is chainable and does not interfere with .then() or .onError().

uploadAvatar(myImage)
    .progress { p in
        // Update a UIProgressView or print to console
        print("Upload progress: \(p * 100)%")
    }
    .then { url in
        print("Upload complete! URL: \(url)")
    }
    .onError { error in
        print("Upload failed: \(error)")
    }

Output:

Starting upload...
Upload progress: 25.0%
Upload progress: 50.0%
Upload progress: 75.0%
Upload complete! URL: https://example.com/avatar.png

Progress blocks will be called on the same thread that the progress closure was called on inside the promise body.