google / promises

Promises is a modern framework that provides a synchronization construct for Swift and Objective-C.
Apache License 2.0
3.81k stars 295 forks source link

Proposal: Progress for all, any, when #35

Closed ghost closed 6 years ago

ghost commented 6 years ago

Hi,

It will be very useful if we have progress: Progress? = nil as last argument to Extensions that get an array of promises like all, any, when

shoumikhin commented 6 years ago

Hi @umbri,

Any usage examples?

ghost commented 6 years ago
let progress = Progress(totalUnitCount: 4) // promises count

when([
    Promise<String> { fulfill, reject in
        DispatchQueue.main.asyncAfter(deadline: .now() + 1, execute: {
            print("1")

            progress.completedUnitCount += 1
            fulfill("1")
        })
    },

    Promise { fulfill, reject in
        DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
            print("2")

            progress.completedUnitCount += 1
            fulfill("2")
        })
    },

    Promise { fulfill, reject in
        DispatchQueue.main.asyncAfter(deadline: .now() + 3, execute: {
            print("3")

            progress.completedUnitCount += 1
            fulfill("3")
        })
    },

    Promise { fulfill, reject in
        DispatchQueue.main.asyncAfter(deadline: .now() + 4, execute: {
            print("4")

            progress.completedUnitCount += 1
            fulfill("4")
        })
    }
    ])
    .then({ (_) in
        print("DONE")
    })
shoumikhin commented 6 years ago

Thank you!

But I don't see a progress passed as an argument to when, as you proposed. The example above can be rewritten as the following without any changes to the Promises APIs:

func subtask(_ overallProgress: Progress) -> Promise<Void> {
  let progress = Progress(totalUnitCount: 10, parent: overallProgress, pendingUnitCount: 1)
  return Promise<Void> {
    guard isEverythingStillOK else {
      progress.cancel()
      throw MyError.somethingIsNotOK
    }
    progress.completedUnitCount = progress.totalUnitCount // Complete the child progress
    return ()
  }
}

let overallProgress = Progress(totalUnitCount: 2)
when(subtask(overallProgress), subtask(overallProgress)).then { _ in
  // At least one subtask has succeeded
}
// Observe overallProgress.fractionCompleted
ghost commented 6 years ago

@shoumikhin Sorry, I just added an example where this can be useful, I thought it will be a syntax sugar for someone who need Progress

i think something like this:

when([Promise<T>], progress: Progress? = nil)
shoumikhin commented 6 years ago

I do like the general idea. Although, at the moment, I believe it should be more involving than just passing an existing progress object to Promises APIs. Because if we went that way, that wouldn't be a big win, because one could track the progress separately, as I showed above. It's just not worth complicating the library APIs for something rarely used, that can be easily achieved the other clear way. But embedding progress reporting and cancellation into Promises would be great. We even have some prototypes internally and still working on that. Once we have anything working, I'll follow up here.

ghost commented 6 years ago

Thank you