我正在设置一个使用promiseKit
作为订购异步任务的方法的应用。我目前有一个设置,确保按顺序完成两个异步功能(称为promises
)(让它们称为1和2),并按顺序完成另一组功能(3和4)。大致是:
import PromiseKit
override func viewDidAppear(_ animated: Bool) {
firstly{
self.promiseOne() //promise #1 happening first (in relation to # 1 and #2)
}.then{_ -> Promise<[String]> in
self.promiseTwo()//promise #2 starting after 1 has completed
}
.catch{ error in
print(error)
}
firstly{
self.promiseThree()//Promise #3 happening first (in relation to #3 and #4)
}.then{_ -> Promise<[String]> in
self.promiseFour()//Promise #4 starting after #3 has completed
}.
.catch{ error in
print(error)
}
}
每个firstly
通过确保第一个函数在第二个函数可以启动之前完成来确保函数的顺序。使用两个单独的firstly
确保1在2之前完成,3在4之前完成,和(重要的是)1和3大致在同一时间开始(在开始时viewDidAppear()
)。这是有目的地完成的,因为1和3彼此不相关并且可以同时开始而没有任何问题(2和4也是如此)。问题是存在第五个承诺,让我们称之为<{em>仅 在 2和4之后运行<{1}}。我可以链接一个promiseFive
确保订单是1,2,3,4,5,但由于1/2和3/4的顺序无关,以这种方式链接它们会浪费时间。
我不确定如何设置它以便firstly
仅在完成2和4时运行。我想在2和4的末尾都有布尔检查函数调用,确保其他promiseFive
已完成,然后调用firstly
但是,由于它们开始异步(1/2和3/4),因此可能会调用promiseFive
两者在同一时间采用这种方法,这显然会产生问题。最好的方法是什么?
答案 0 :(得分:2)
您可以使用when或join在多个其他承诺完成后启动某些内容。不同之处在于他们如何处理失败的承诺。听起来你想要加入。这是一个具体的,虽然简单的例子。
第一个代码块是如何创建2个promise链,然后在开始下一个任务之前等待它们完成的示例。正在完成的实际工作被抽象为一些功能。专注于这段代码,因为它包含您需要的所有概念信息。
let chain1 = firstly(execute: { () -> (Promise<String>, Promise<String>) in
let secondPieceOfInformation = "otherInfo" // This static data is for demonstration only
// Pass 2 promises, now the next `then` block will be called when both are fulfilled
// Promise initialized with values are already fulfilled, so the effect is identical
// to just returning the single promise, you can do a tuple of up to 5 promises/values
return (fetchUserData(), Promise(value: secondPieceOfInformation))
}).then { (result: String, secondResult: String) -> Promise<String> in
self.fetchUpdatedUserImage()
}
let chain2 = firstly {
fetchNewsFeed() //This promise returns an array
}.then { (result: [String : Any]) -> Promise<String> in
for (key, value) in result {
print("\(key) \(value)")
}
// now `result` is a collection
return self.fetchFeedItemHeroImages()
}
join(chain1, chain2).always {
// You can use `always` if you don't care about the earlier values
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(self.methodStart)
print(String(format: "All promises finished %.2f seconds later", executionTime))
}
PromiseKit使用closures来提供它的API。闭包的范围就像if
语句一样。如果您在if
语句的范围内定义了一个值,那么您将无法在该范围之外访问该值。
您可以通过多种方式将多个数据传递到下一个then
块。
chain2
chain1
在选择方法时,您需要使用最佳判断。
import UIKit
import PromiseKit
class ViewController: UIViewController {
let methodStart = Date()
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
<<Insert The Other Code Snippet Here To Complete The Code>>
// I'll also mention that `join` is being deprecated in PromiseKit
// It provides `when(resolved:)`, which acts just like `join` and
// `when(fulfilled:)` which fails as soon as any of the promises fail
when(resolved: chain1, chain2).then { (results) -> Promise<String> in
for case .fulfilled(let value) in results {
// These promises succeeded, and the values will be what is return from
// the last promises in chain1 and chain2
print("Promise value is: \(value)")
}
for case .rejected(let error) in results {
// These promises failed
print("Promise value is: \(error)")
}
return Promise(value: "finished")
}.catch { error in
// With the caveat that `when` never rejects
}
}
func fetchUserData() -> Promise<String> {
let promise = Promise<String> { (fulfill, reject) in
// These dispatch queue delays are standins for your long-running asynchronous tasks
// They might be network calls, or batch file processing, etc
// So, they're just here to provide a concise, illustrative, working example
DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(self.methodStart)
print(String(format: "promise1 %.2f seconds later", executionTime))
fulfill("promise1")
}
}
return promise
}
func fetchUpdatedUserImage() -> Promise<String> {
let promise = Promise<String> { (fulfill, reject) in
DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(self.methodStart)
print(String(format: "promise2 %.2f seconds later", executionTime))
fulfill("promise2")
}
}
return promise
}
func fetchNewsFeed() -> Promise<[String : Any]> {
let promise = Promise<[String : Any]> { (fulfill, reject) in
DispatchQueue.global().asyncAfter(deadline: .now() + 1.0) {
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(self.methodStart)
print(String(format: "promise3 %.2f seconds later", executionTime))
fulfill(["key1" : Date(),
"array" : ["my", "array"]])
}
}
return promise
}
func fetchFeedItemHeroImages() -> Promise<String> {
let promise = Promise<String> { (fulfill, reject) in
DispatchQueue.global().asyncAfter(deadline: .now() + 2.0) {
let methodFinish = Date()
let executionTime = methodFinish.timeIntervalSince(self.methodStart)
print(String(format: "promise4 %.2f seconds later", executionTime))
fulfill("promise4")
}
}
return promise
}
}
承诺3 1.05秒后 数组[&#34;我&#34;,&#34;数组&#34;]
key1 2017-07-18 13:52:06 +0000
承诺1 2.04秒后 承诺4 3.22秒后 promise2 4.04秒后 所有承诺在4.04秒后完成 承诺价值是:promise2
承诺价值是:promise4
答案 1 :(得分:1)
细节取决于这些不同承诺的类型,但你基本上可以返回1的承诺,然后将2作为一个承诺,并返回3的承诺,然后返回4作为另一个承诺,然后使用{{ 1}}同时相对于彼此运行这两个承诺序列,但仍然享受这些序列中的连续行为。例如:
when
这种情况可能会导致您保持问题相当通用的尝试可能会让您更难以了解如何在您的案例中应用此答案。所以,如果你磕磕绊绊,你可能想要更具体地说明这四个承诺正在做什么以及它们相互传递什么(因为这种结果从一个传递到另一个是承诺的优雅特征之一)。