Last active
October 17, 2017 01:11
-
-
Save fpg1503/a5911852eb5bfff7e35c7b17d15c823d to your computer and use it in GitHub Desktop.
[WIP] Promises from scratch
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 | |
import PlaygroundSupport | |
enum PromiseState<T> { | |
case pending | |
case fulfilled(T) | |
case rejected(Error) | |
var isPending: Bool { | |
switch self { | |
case .pending: return true | |
default: return false | |
} | |
} | |
} | |
class Promise<T> { | |
typealias Resolve = (T) -> Void | |
typealias Reject = (Error) -> Void | |
typealias ResolveOrReject = (_ resolve: @escaping Resolve, _ reject: @escaping Reject) -> Void | |
var state: PromiseState<T> { | |
didSet { | |
guard oldValue.isPending, | |
!state.isPending else { | |
print("Attempt to go from \(oldValue) to \(state), which is an invalid transition, reverting") | |
state = oldValue | |
return | |
} | |
handlePendencies() | |
} | |
} | |
func handlePendencies() { | |
switch state { | |
case .pending: break //Nothing to do here | |
case .fulfilled(let value): | |
if !pendencies.isEmpty { | |
pendencies.forEach { $0(value) } | |
pendencies = [] | |
} | |
case .rejected(let error): print(error) | |
} | |
} | |
func resolver(_ newValue: T) -> Void { | |
self.state = .fulfilled(newValue) | |
} | |
func rejecter(_ error: Error) -> Void { | |
self.state = .rejected(error) | |
print(error) | |
} | |
init(_ resolveOrReject: ResolveOrReject) { | |
self.state = .pending | |
resolveOrReject(resolver, rejecter) | |
} | |
var pendencies: [(T) -> Void] = [] { | |
didSet { | |
handlePendencies() | |
} | |
} | |
func then<U>(transformer: @escaping (T) -> U) -> Promise<U> { | |
return Promise<U>() { (resolve, reject) in | |
let resolved: (T) -> Void = { resolvedValue in | |
let transformed = transformer(resolvedValue) | |
resolve(transformed) | |
} | |
pendencies.append(resolved) | |
} | |
} | |
} | |
struct TestError: Error { } | |
let promise = Promise<Int>() { resolve, reject in | |
resolve(2) | |
resolve(3) | |
reject(TestError()) | |
} | |
promise.then { | |
print($0) | |
} | |
promise.then { | |
print("Value: \($0)") | |
} | |
let foo = Promise({ (resolve, reject) in | |
DispatchQueue(label: "Test").asyncAfter(deadline: .now() + 0.5, execute: { | |
resolve(1) | |
}) | |
}).then { | |
print($0) | |
} | |
print("created promise") | |
PlaygroundPage.current.needsIndefiniteExecution = true |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment