Swift PromiseKit: Equivalent to when() which executes sequentially?

可紊 提交于 2020-04-13 09:10:19

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!