-
-
Save phucledien/73bc80204712be15ebdb6b62c091ce98 to your computer and use it in GitHub Desktop.
The minimum viable promise in Swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
struct Promise<T> { | |
typealias ResultType = Result<T, Error> | |
typealias ResultObserver = (ResultType) -> Void | |
typealias CreatorFunction = (@escaping ResultObserver) -> Void | |
private let creatorFunction: CreatorFunction | |
init(creatorFunction: @escaping CreatorFunction) { | |
self.creatorFunction = creatorFunction | |
} | |
func then<E>(_ f: @escaping (T) -> E) -> Promise<E> { | |
return Promise<E> { observer in | |
self.creatorFunction { r in | |
observer(r.map(f)) | |
} | |
} | |
} | |
static func all(_ promises: [Promise<T>], on queue: DispatchQueue = .main) -> Promise<[T]> { | |
return Promise<[T]> { observer in | |
let group = DispatchGroup() | |
var values = [T]() | |
var hasFailed = false | |
for promise in promises { | |
group.enter() | |
promise.then { r in | |
switch r { | |
case let .success(value): | |
values.append(value) | |
case let .failure(error): | |
observer(.failure(error)) | |
hasFailed = true | |
} | |
group.leave() | |
} | |
} | |
group.notify(queue: queue) { | |
guard !hasFailed else { | |
return | |
} | |
observer(.success(values)) | |
} | |
} | |
} | |
func then<E>(_ f: @escaping (T) -> Promise<E>) -> Promise<E> { | |
return Promise<E> { observer in | |
self.creatorFunction { firstResult in | |
switch firstResult { | |
case .success(let successResult): | |
f(successResult).creatorFunction { transformedResult in | |
observer(transformedResult) | |
} | |
case .failure(let error): | |
observer(.failure(error)) | |
} | |
} | |
} | |
} | |
@discardableResult func then(_ f: @escaping (ResultType) -> Void) -> Self { | |
creatorFunction { r in f(r) } | |
return self | |
} | |
} | |
func getNumber() -> Promise<Int> { | |
return .init { (observer) in | |
observer(.success(5)) | |
} | |
} | |
func getTextFromNumber(_ number: Int) -> Promise<String> { | |
return .init { observer in | |
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { | |
observer(.success("Fernando \(number)")) | |
} | |
} | |
} | |
getNumber() | |
.then(getTextFromNumber) | |
.then { r in | |
switch r { | |
case .success(let text): | |
print(text) | |
case .failure(let error): | |
print(error) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment