Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
import UIKit
import Foundation
func test(named: String,
_ work: (_ assert: @escaping (Bool) -> Void, _ done: @escaping () -> Void) -> Void) {
var testPass = true
var assertCount = 0
let assert: (Bool) -> Void = { value in
assertCount = assertCount + 1
testPass = testPass && value
}
let done: () -> Void = {
if testPass {
print("• Test \(named) passed (\(assertCount) assertions)")
} else {
print("× Test \(named) failed (\(assertCount) assertions)")
}
}
work(assert, done)
}
func after(_ timeInterval: TimeInterval = 0.1, work: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + timeInterval, execute: work)
}
//: ## Promise
//func asyncWork(completion: (String) -> Void) {
// // ...
// completion("test")
//}
//
//asyncWork { value in
// print(value)
//}
//
//let asyncPromise = Promise<String> { resolve in
// // ...
// resolve("test")
//}
//
//asyncPromise.then { value in
// print(value)
//}
class Promise<Value> {
enum State<T> {
case pending
case resolved(T)
}
private var state: State<Value> = .pending
private var callbacks: [(Value) -> Void] = []
init(executor: (_ resolve: @escaping (Value) -> Void) -> Void) {
executor(resolve)
}
// observe
public func then(_ onResolved: @escaping (Value) -> Void) {
callbacks.append(onResolved)
triggerCallbacksIfResolved()
}
// flatMap
public func then<NewValue>(_ onResolved: @escaping (Value) -> Promise<NewValue>) -> Promise<NewValue> {
return Promise<NewValue> { resolve in
then { value in
onResolved(value).then(resolve)
}
}
}
// map
public func then<NewValue>(_ onResolved: @escaping (Value) -> NewValue) -> Promise<NewValue> {
return then { value in
return Promise<NewValue> { resolve in
resolve(onResolved(value))
}
}
}
private func resolve(value: Value) {
updateState(to: .resolved(value))
}
private func updateState(to newState: State<Value>) {
guard case .pending = state else { return }
state = newState
triggerCallbacksIfResolved()
}
private func triggerCallbacksIfResolved() {
guard case let .resolved(value) = state else { return }
callbacks.forEach { callback in
callback(value)
}
callbacks.removeAll()
}
}
//: ## Tests
//test(named: "0. Executor function is called immediately") { assert, done in
// var string: String = ""
// _ = Promise { string = "foo" }
// assert(string == "foo")
// done()
//}
test(named: "1.1 Resolution handler is called when promise is resolved sync") { assert, done in
let string: String = "foo"
let promise = Promise<String> { resolve in
resolve(string)
}
promise.then { (value: String) in
assert(string == value)
done()
}
}
test(named: "1.2 Resolution handler is called when promise is resolved async") { assert, done in
let string: String = "foo"
let promise = Promise<String> { resolve in
after(0.1) {
resolve(string)
}
}
promise.then { (value: String) in
assert(string == value)
done()
}
}
test(named: "2.1 Promise supports many resolution handlers sync") { assert, done in
let string: String = "foo"
let promise = Promise<String> { resolve in
resolve(string)
}
promise.then { value in
assert(string == value)
}
promise.then { value in
assert(string == value)
done()
}
}
test(named: "2.2 Promise supports many resolution handlers async") { assert, done in
let string: String = "foo"
let promise = Promise<String> { resolve in
after(0.1) {
resolve(string)
}
}
promise.then { value in
assert(string == value)
}
promise.then { value in
assert(string == value)
done()
}
}
test(named: "3. Resolution handlers can be chained") { assert, done in
let string: String = "foo"
let promise = Promise<String> { resolve in
after(0.1) {
resolve(string)
}
}
promise
.then { value in
return Promise<String> { resolve in
after(0.1) {
resolve(value + value)
}
}
}
.then { value in
assert(string + string == value)
done()
}
}
test(named: "4. Chaining works with non promise return values") { assert, done in
let string: String = "foo"
let promise = Promise<String> { resolve in
after(0.1) {
resolve(string)
}
}
promise
.then { value -> String in
return value + value
}
.then { value in
assert(string + string == value)
done()
}
}
//: ## Example
struct User {
let id: Int
let name: String
}
func fetchIds() -> Promise<[Int]> {
return Promise { resolve in
resolve([0])
}
}
func fetchUser(id: Int) -> Promise<User> {
return Promise { resolve in
after(0.1) {
resolve(User(id: id, name: "Bob"))
}
}
}
fetchIds()
.then { ids in // flatMap
return fetchUser(id: ids[0])
}
.then { user in // map
return user.name
}
.then { name in // observe
print(name)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.