Promissum


Promissum 是一个用 Swift 编写的 promises 库。它具有一些来自函数式编程的常用功能,例如 mapflatMap

它有一些有用的组合器来处理 promises,例如:whenAll 用于在多个 promises 完成时执行某些操作,以及 whenAny 用于在列表中的任何一个 promise 完成时执行某些操作。以及它们的二元对应物:whenBothwhenEither

当用于组合来自不同库的异步操作时,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
  }

Async/Await

通过 .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 是正交的。

组合器

下面列出的是此库提供的一些方法和函数。更多文档可在内联文档中找到。

Promise 的实例方法

用于处理 Promises 的函数

Dispatch queues

Promises 可以在不同的线程或队列上调用处理程序。处理程序是所有提供给诸如 .then.trap.map.flatMap 等方法的闭包。

如果未指定其他内容,默认情况下,所有处理程序都将在主队列上调用。这样,您可以自由更新 UI,而无需担心手动调用 dispatch_async

但是,可以轻松更改 promise 使用的 dispatch 队列。通过以下两种方式之一

  1. 在创建 PromiseSource 时设置 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
  }
  1. 或者,使用 .dispatchOn 组合器创建一个新的 promise
let 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)
  }

安装

Swift Package Manager

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 版本,这些版本仍然有效。

版本发布

许可 & 鸣谢

Promissum 由 Tom Lokhorst 编写,并根据 MIT 许可证 提供,因此可以随意在商业和非商业项目中使用它。