Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/davidask/futures

Lightweight promises for iOS, macOS, tvOS, watchOS, and Linux
https://github.com/davidask/futures

async futures ios macos promises server-side-swift swift tvos watchos

Last synced: 6 days ago
JSON representation

Lightweight promises for iOS, macOS, tvOS, watchOS, and Linux

Awesome Lists containing this project

README

        

# Futures
![Tests](https://github.com/davidask/Futures/workflows/Tests/badge.svg)

Futures is a cross-platform framework for simplifying asynchronous programming, written in Swift. It's lightweight, fast, and easy to understand.

### Supported Platforms

* Ubuntu 14.04
* macOS 10.9
* tvOS 9.0
* iOS 8.0
* watchOS 2.0

### Architecture

Fundamentally, Futures is a very simple framework, that consists of two types:

* `Promise`, a single assignment container producing a `Future`
* `Future`, a read-only container resolving into either a value, or an error

In many promise frameworks, a promise is undistinguished from a future. This introduces mutability of a promise that gets passed around. In Futures, a `Future` is the observable value while a `Promise` is the function that sets the value.

Futures are observed, by default, on a single concurrent dispatch queue. This queue can be modified by assigning a different queue to `DispatchQueue.futures`. You can also specify a queue of your choice to each callback added to a future .

A future is regarded as:

* `resolved`, if its value is set
* `fulfilled`, if the value is set, and successful
* `rejected`, if the value is set, and a failure (error)

## Usage

When a function returns a `Future`, you can either decide to observe it directly, or continue with more asynchronous tasks. For observing, you use:

* `whenResolved`, if you're interested in both a value and a rejection error
* `whenFulfilled`, if you only care about the values
* `whenRejected`, if you only care about the error

If you have more asynchronous work to do based on the result of the first future, you can use

* `flatMap()`, to execute another future based on the result of the current one
* `flatMapIfRejected()`, to recover from a potential error resulting from the current future
* `flatMapThrowing()`, to transform the fulfilled value of the current future or return a rejected future
* `map()`, to transform the fulfilled value of the current future
* `recover()`,to transform a rejected future into a fulfilled future
* `always()`, to execute a `Void` returning closure regardless of whether the current future is rejected or resolved
* `and()`, to combine the result of two futures into a single tuple
* `Future.reduce()`, to combine the result of multiple futures into a single future

Note that you can specify an observation dispatch queue for all these functions. For instance, you can use `flatMap(on: .main)`, or `.map(on: .global())`. By default, the queue is `DispatchQueue.futures`.

As a simple example, this is how some code may look:

```swift
let future = loadNetworkResource(
from: URL("http://someHost/resource")!
).flatMapThrowing { data in
try jsonDecoder.decode(SomeType.self, from: data)
}.always {
someFunctionToExecuteRegardless()
}

future.whenFulfilled(on: .main) { someType in
// Success
}

future.whenRejected(on: .main) { error in
// Error
}
```

To create your functions returning a `Future`, you create a new pending promise, and resolve it when appropriate.

```swift
func performAsynchronousWork() -> Future {
let promise = Promise()

DispatchQueue.global().async {
promise.fulfill(someString)

// If error
promise.reject(error)
}

return promise.future
}
```

You can also use shorthands.

```swift
promise {
try jsonDecoder.decode(SomeType.self, from: data)
} // Future
```

Or shorthands which you can return from asynchronously.
```swift
promise(String.self) { completion in
/// ... on success ...
completion(.fulfill("Some string"))
/// ... if error ...
completion(.reject(anError))
} // Future
```

## Documentation

The complete documentation can be found [here](https://davidask.github.io/Futures/).

## Getting started

Futures can be added to your project either using [Carthage](https://github.com/Carthage/Carthage) or Swift package manager.

If you want to depend on Futures in your project, it's as simple as adding a `dependencies` clause to your `Package.swift`:

```swift
dependencies: [
.package(url: "https://github.com/davidask/Futures.git", from: "1.6.0")
]
```

Or, add a dependency in your `Cartfile`:

```
github "davidask/Futures"
```

More details on using Carthage can be found [here](https://github.com/Carthage/Carthage#quick-start).

Lastly, import the module in your Swift files

```swift
import Futures
```

## Contribute
Please feel welcome contributing to **Futures**, check the ``LICENSE`` file for more info.

## Credits

David Ask