CancellablePromiseKit
CancellablePromiseKit 是 PromiseKit 的扩展。Promise 是异步操作的一种抽象,可以是成功或失败。由该库提供的 CancellablePromise 扩展了这一概念,代表了可取消/中止的任务。
安装
CancellablePromiseKit 通过 CocoaPods 提供。要安装它,只需将以下行添加到 Podfile:
pod 'CancellablePromiseKit'
要运行单元测试,首先克隆仓库,然后从 Example 目录运行 pod install
。
创建可取消的 Promise
创建 CancellablePromise 的方法与创建 Promise 的方法类似。
func startTask() -> CancellablePromise<String> {
let task = Task(…)
return CancellablePromise<String> { resolver in
task.completion = { (value, error) in
resolver.resolve(value, error)
}
let cancel = {
task.stop()
print("Task was cancelled")
}
return cancel
}
}
let runningTask = startTask()
此初始化器几乎与 Promise 的那个相同。然而,该块必须返回一个处理程序,当 CancellablePromise 被取消时将执行它。它必须执行必要的步骤来中止底层任务。
取消
CancellablePromise
有一个 cancel()
方法用于停止任务
runningTask.cancel()
调用 cancel()
会用 CancellablePromiseError.cancelled
拒绝承诺。只有当您将策略设置为 .allErrors
时,承诺链中的 catch
处理器才会被调用
runningTask.catch(policy: .allErrors) { error in
// Will be called with error being CancellablePromiseError.cancelled
}
runningTask.cancel()
race
和 when
变体带有 autoCancel
PromiseKit
的 race
函数使您能够等待列表中的第一个任务完成。您可以使用此任务的结果进行进一步处理。但是,其他任务会继续执行,尽管它们的最终结果将被忽略。如果您使用 CancellablePromise
,则有一个特殊的重载函数 race(:, autoCancel:)
,它提供了另一个名为 autoCancel
的参数。如果您将其设置为 true
,则列表中的所有其他任务都将被取消
race([cancellablePromise1, cancellablePromise2, cancellablePromise3], autoCancel: true)
如果 cancellablePromise1
将会成功解决,cancellablePromise2
和 cancellablePromise3
将会被自动取消。因此,如果这些代表大型下载,例如,就不会浪费更多的带宽。
类似地,还有 when(resolved:, autoCancel:)
和 when(fulfilled:, autoCancel:)
,如果其中一个失败,将会取消所有的承诺
race(:, autoCancel:)
、when(resolved:, autoCancel:)
和 when(fulfilled:, autoCancel:)
返回一个可以取消的 CancellablePromise
,它自身可以被取消。取消此承诺将仅在 autoCancel
为 true
时取消传入的承诺。
autoCancel
参数默认为 false
,因此省略它将产生与常规 PromiseKit
相同的行为。
then
重载的 then
函数允许您链 CancellablePromise
,这将创建另一个 CancellablePromise
let cancellableChain = cancellablePromise1.then {
cancellablePromise2
}
cancellableChain.cancel()
取消链式命令将取消所有包含的挂起承诺,即在此示例中的 cancellablePromise1
和 cancellablePromise2
。
asPromise
和 asCancellable
如果您想在单个表达式(如 when
或 race
)中使用 Promise
和 CancellablePromise
,则可以在它们之间进行转换。每个 CancellablePromise
都提供 asPromise()
,每个 Promise
都提供 asCancellable()
。在后者上调用 cancel()
将导致拒绝,但您调用的 asCancellable()
的那个基础 Promise 将继续为 pending
。
CancellablePromise
其他初始化方式
CancellablePromise
不是 Promise
的子类,而是其包装器。您可以通过传递一个 Promise 和一个取消块来创建一个新实例
let existingPromise, existingResolver = Promise<String>.pending()
let cancelFunction = { existingResolver.reject(MyError()) }
let cancellablePromise = CancellablePromise<String>(using: existingPromise, cancel: cancelFunction)
在某些情况下,您使用其他 Promise 来构建可取消的任务。在这种情况下,您可以使用提供 cancelPromise
的初始化器。它是一个永远不解决的 Promise
,但当调用 cancel()
时将拒绝。将它放入一个 race
与另一个 Promise 一起允许您等待该 Promise 解决,除非进程取消。以下示例并行执行两个任务,然后执行第三个任务。整个过程可以在任何时候取消
let cancellablePromise = CancellablePromise<String>(wrapper: { cancelPromise in
let task1: Promise<String> = Task()
let task2: Promise<String> = Task()
let tasks = when(fulfilled: task1, task2)
return firstly {
race(tasks.asVoid(), cancelPromise)
}.then {
let value1 = task1.value!
let value2 = task2.value!
let task3: Promise<String> = AnotherTask(value1, value2)
return race(task3.asVoid(), cancelPromise).map {
task3.value!
}
}
})
在这个示例中调用 cancellablePromise.cancel()
将导致 cancelPromise
拒绝,这将导致所有 race
调用及其下的整个 cancellablePromise
都将拒绝。
when
的 cancelPromise
变体
如前例所示,构建可取消的 Promise 通常涉及等待另一个 Promise 完成,同时期待取消。使用 race
来构建需要将 Promise 转换为 Promise
,这使得获取解决值变得繁琐。因此,存在 when(:, while:)
重载。
而不是
let task: Promise<String> = ...
race(task.asVoid(), cancelPromise).then {
let value = tasks.value!
// use value
}
你可以说
when(task, while: cancelPromise).then { value in
// use value
}
上面的例子可以重写为
let cancellablePromise = CancellablePromise<String>(wrapper: { cancelPromise in
let task1: Promise<String> = Task()
let task2: Promise<String> = Task()
return firstly {
let tasks = when(fulfilled: task1, task2)
return when(tasks, while: cancelPromise)
}.then { (value1, value2) in
let task3: Promise<String> = AnotherTask(value1, value2)
return when(task3, while: cancelPromise)
}
})
为了在 cancelPromise
拒绝时执行某些操作,请使用 catch
let taskWithCancel = when(task, while: cancelPromise).then { value in
// ...
}
taskWithCancel.catch(policy: .allErrors) { error in
switch error {
case CancellablePromiseError.cancelled:
// do something to cancel the underlying task
default:
// task failed
}
}
TODO
- 应该存在对
done
、get
、catch
等操作的复写,返回一个CancellablePromise
。当前,Thenable
的实现只会返回一个普通的Promise
。 - 应该存在一个
firstly
操作,用于CancellablePromise
。 - 在
Guarantee
中应该有一个asCancellable()
方法,返回一个CancellablePromise
。不会存在一个,因为一个提供取消任务的目标不能同时声称总是能满足。CancellableGuarantee
PromiseKit
为race
和when
提供了许多复写,可以接收数组、可变参数等。CancellablePromiseKit
也可以做到。- 可能会有类似于
pending
、value
等工厂函数,如PromiseKit
。
作者
Johannes Dörr, [email protected]
许可证
CancellablePromiseKit 在 MIT 许可证下可用。关于更多信息,请参阅 LICENSE 文件。