Promissum 是一个用 Swift 编写的 promises 库。它具有一些来自函数式编程的常用功能,例如 map
和 flatMap
。
它有一些有用的组合器来处理 promises,例如:whenAll
用于在多个 promises 完成时执行某些操作,以及 whenAny
用于在列表中的任何一个 promise 完成时执行某些操作。以及它们的二元对应物:whenBoth
和 whenEither
。
当用于组合来自不同库的异步操作时,Promissum 真正发挥作用。目前有一些针对 UIKit 和 Alamofire 的基本扩展,非常欢迎为其他库扩展做出贡献。
这个库有大量的回归测试、文档,并且已在 Q42 的几个备受瞩目的生产应用程序中使用。
此示例演示了 Alamofire+Promise 扩展。
在此示例中,JSON 数据从 Github API 加载。然后对其进行解析,并存储到本地缓存中。如果两者都成功,则结果将显示给用户;如果其中任何一个失败,则会向用户显示错误描述。
let url = "https://api.github.com/repos/tomlokhorst/Promissum"
Alamofire.request(url).responseJSONPromise()
.map(parseJson)
.flatMap(storeInLocalCache)
.then { project in
// Show project name and description
self.nameLabel.text = project.name
self.descriptionLabel.text = project.descr
UIView.animate(withDuration: 0.5) {
self.detailsView.alpha = 1
}
}
.trap { e in
// Either an Alamofire error or a LocalCache error occured
self.errorLabel.text = e.localizedDescription
self.errorView.alpha = 1
}
通过 .asyncValue
和 .asyncResult
属性,以及自定义的 Promise
初始化器,可以使用 Swift 的 async await 功能。
// Go from Promise to async/await
func downloadProject(url: URL) async throws -> Project {
let data = try await downloadPromise(url: url).asyncValue
let project = try parse(data)
return project
}
// Go from async/await to Promise
func submitProject(project: Project) -> Promise<Void, Error> {
Promise {
let data = try encode(project)
try await upload(data)
}
}
Promissum 不支持取消,因为取消与 promises 不兼容。Promises 是未来的值,值是无法取消的。如果您确实需要取消(通常很有用),请查看 Tasks 或 Rx 而不是 promises。我没有使用任何 Swift Task/Rx 库的经验,因此我无法推荐特定的库。
但是,如果您希望向 PromiseSource 添加取消功能,则可以使用我编写的 swift-cancellationtoken 库。但这与 promises 是正交的。
下面列出的是此库提供的一些方法和函数。更多文档可在内联文档中找到。
.map(transform: Value -> NewValue)
返回一个 Promise,其中包含将函数映射到 promise 值的结果。
.flatMap(transform: Value -> Promise<NewValue, Error>)
返回将函数映射到 promise 值后的扁平化结果。
.mapError(transform: Error -> NewError)
返回一个 Promise,其中包含将函数映射到 promise 错误的结果。
.flatMapError(transform: Error -> Promise<Value, NewError>)
返回将函数映射到 promise 错误后的扁平化结果。
.dispatch(on queue: DispatchQueue)
返回一个新的 promise,它将在指定的 dispatch_queue 上执行所有回调。请参阅 dispatch queues
whenBoth(promiseA: Promise<A, Error>, _ promiseB: Promise<B, Error>)
创建一个 Promise,当 whenBoth
的两个参数都 resolve 时,该 Promise resolve。
whenAll(promises: [Promise<Value, Error>])
创建一个 Promise,当所有提供的 Promises 都 resolve 时,该 Promise resolve。
whenEither(promise1: Promise<Value, Error>, _ promise2: Promise<Value, Error>)
创建一个 Promise,当任一参数 resolve 时,该 Promise resolve。
whenAny(promises: [Promise<Value, Error>])
创建一个 Promise,当任何一个参数 Promises resolve 时,该 Promise resolve。
Promises 可以在不同的线程或队列上调用处理程序。处理程序是所有提供给诸如 .then
、.trap
、.map
和 .flatMap
等方法的闭包。
如果未指定其他内容,默认情况下,所有处理程序都将在主队列上调用。这样,您可以自由更新 UI,而无需担心手动调用 dispatch_async
。
但是,可以轻松更改 promise 使用的 dispatch 队列。通过以下两种方式之一
let background = DispatchQueue.global(qos: .background)
let source = PromiseSource<Int, Never>(dispatch: .queue(background))
source.promise
.then { x in
// Handler is called on background queue
}
.dispatchOn
组合器创建一个新的 promiselet background = DispatchQueue.global(qos: .background)
somePromise()
.dispatch(on: background)
.then { x in
// Handler is called on background queue
}
为了方便起见,还有 .dispatchMain
在后台队列上完成一些工作后,返回到主队列
let background = DispatchQueue.global(qos: .background)
somePromise()
.dispatch(on: background)
.map { expensiveComputation($0) }
.dispatchMain()
.then { x in
self.updateUi(x)
}
SPM 是 Swift 项目的依赖管理工具。
一旦您设置好 SPM,请使用 Xcode 或编辑 Package.swift 添加依赖项
dependencies: [
.package(url: "https://github.com/tomlokhorst/Promissum.git", from: "7.1.0"),
]
注意: 以前版本的 Promissum 支持 CocoaPods,现在已不再支持。如果您仍然需要 pods 支持,可以使用此软件包的 5.x.x 版本,这些版本仍然有效。
delay
和相关函数dispatchOn
方法,用于在不同的队列上调度whenAnyFinalized
组合器Promissum 由 Tom Lokhorst 编写,并根据 MIT 许可证 提供,因此可以随意在商业和非商业项目中使用它。