问题
I'm using PromiseKit with Swift, which has been very handy so far. One of the functions they provide is when()
, which allows you to have an array of any number of promises and execute something only once ALL of them have completed.
However, the promises in the array are executed in parallel. I have not found any function that allows me to execute them sequentially. I've tried to write a recursive function of my own, but it doesn't appear to be executing the promises in the order in which they are in the array, and I get the occasional "Promise deallocated" bug. Please help!
static func executeSequentially(promises: [Promise<Void>]) -> Promise<Void> {
return Promise<Void> { fulfil, reject in
var mutablePromises = promises
if mutablePromises.count > 0 {
mutablePromises.first!
.then { _ -> Promise<Void> in
print("DEBUG: \(mutablePromises.count) promises in promise array.")
mutablePromises.remove(at: 0)
return executeSequentially(promises: mutablePromises)
}.catch { error in
print("DEBUG: Promise chain rejected.")
reject(error)
}
} else {
print("DEBUG: Promise chain fulfilled.")
fulfil(())
}
}
}
回答1:
I think you may want to examine why you even want such functionality. Consider:
If the result of one promise is needed as input for the next, then they MUST be sequential (
then()
)If the result of one promise is not needed as input for the next, then there should be NO NEED for them to be sequential, and the most efficient use of concurrency should be applied by the framework or platform (this will mean parallel execution in most cases)
If promises that do not have any input / output dependency on each other have to run in a specific sequence, it implies that you are depending on a certain order of side effects to happen. If that is the case, I would suggest cleaning that up instead of fixing the problem downstream with a sequential when()
.
If this isn't helpful, then perhaps consider adding information to your question that explains why this sequential execution of independent promises is important. You may get some good suggestions for either solving it another way, or accomplishing what you want to do using a combination of existing when()
and then()
functionality.
回答2:
Here's an extension that takes an array of promises and returns a new promise with all the individual promises chained together to run serially. I've modified the version found here to work with Swift 5 / PromiseKit 7 alpha: https://gist.github.com/kashifshaikh/416b9ffbd300eb680fad3641b6ec53ea
The accompanying post from the original author can be found here: https://medium.com/@peatiscoding/promisekit-chaining-3c957a8ace24
import Foundation
import PromiseKit
extension Promise {
/// Returns a single Promise that you can chain to. Wraps the chains of promises passed into the array into a serial promise to execute one after another using `promise1.then { promise2 }.then ...`
///
/// - Parameter promisesToExecuteSerially: promises to stitch together with `.then` and execute serially
/// - Returns: returns an array of results from all promises
public static func chainSerially<T>(_ promisesToExecuteSerially:[Promise<T>]) -> Promise<[T]> {
// Create an array of closures that return `Promise<T>`
var promises = promisesToExecuteSerially.map { p -> () -> Promise<T> in
return { p }
}
// Return a single promise that is fullfilled when
// all passed promises in the array are fullfilled serially
return Promise<[T]> { seal in
var outResults = [T]()
if promises.count == 0 {
seal.fulfill(outResults)
} else {
let initial = promises.removeFirst()
let finalPromise:Promise<T> = promises.reduce(initial()) { (result: Promise<T>, next: @escaping ()->Promise<T>) in
return result.then { result -> Promise<T> in
outResults.append(result)
return next()
}
}
// Result of the final promise executed
// and seal fullfilled here
finalPromise.done { result -> Void in
outResults.append(result)
seal.fulfill(outResults)
}.catch { error in
seal.reject(error)
}
}
}
}
}
来源:https://stackoverflow.com/questions/48350305/swift-promisekit-equivalent-to-when-which-executes-sequentially