CancellablePromiseKit 0.3.0

CancellablePromiseKit 0.3.0

Johannes Dörr 维护。



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()

racewhen 变体带有 autoCancel

PromiseKitrace 函数使您能够等待列表中的第一个任务完成。您可以使用此任务的结果进行进一步处理。但是,其他任务会继续执行,尽管它们的最终结果将被忽略。如果您使用 CancellablePromise,则有一个特殊的重载函数 race(:, autoCancel:),它提供了另一个名为 autoCancel 的参数。如果您将其设置为 true,则列表中的所有其他任务都将被取消

race([cancellablePromise1, cancellablePromise2, cancellablePromise3], autoCancel: true)

如果 cancellablePromise1 将会成功解决,cancellablePromise2cancellablePromise3 将会被自动取消。因此,如果这些代表大型下载,例如,就不会浪费更多的带宽。

类似地,还有 when(resolved:, autoCancel:)when(fulfilled:, autoCancel:),如果其中一个失败,将会取消所有的承诺

race(:, autoCancel:)when(resolved:, autoCancel:)when(fulfilled:, autoCancel:) 返回一个可以取消的 CancellablePromise,它自身可以被取消。取消此承诺将仅在 autoCanceltrue 时取消传入的承诺。

autoCancel 参数默认为 false,因此省略它将产生与常规 PromiseKit 相同的行为。

then

重载的 then 函数允许您链 CancellablePromise,这将创建另一个 CancellablePromise

let cancellableChain = cancellablePromise1.then {
    cancellablePromise2
}
cancellableChain.cancel()

取消链式命令将取消所有包含的挂起承诺,即在此示例中的 cancellablePromise1cancellablePromise2

asPromiseasCancellable

如果您想在单个表达式(如 whenrace)中使用 PromiseCancellablePromise,则可以在它们之间进行转换。每个 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 都将拒绝。

whencancelPromise 变体

如前例所示,构建可取消的 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

  • 应该存在对 donegetcatch 等操作的复写,返回一个 CancellablePromise。当前,Thenable 的实现只会返回一个普通的 Promise
  • 应该存在一个 firstly 操作,用于 CancellablePromise
  • Guarantee 中应该有一个 asCancellable() 方法,返回一个 CancellablePromise。不会存在一个 CancellableGuarantee,因为一个提供取消任务的目标不能同时声称总是能满足。
  • PromiseKitracewhen 提供了许多复写,可以接收数组、可变参数等。CancellablePromiseKit 也可以做到。
  • 可能会有类似于 pendingvalue 等工厂函数,如 PromiseKit

作者

Johannes Dörr, [email protected]

许可证

CancellablePromiseKit 在 MIT 许可证下可用。关于更多信息,请参阅 LICENSE 文件。