Skip to content

Rethinking progress #264

@briancavalier

Description

@briancavalier

Promise progress is problematic for several reasons. One big one is that progress values are opaque (they might be numbers, objects, arrays, etc.). A promise library can't combine them in any meaningful way. For example, when.all can't combine the progress values from its input promises. It must simply pass them through. This means that the promise returned by when.all might receive heterogenous values: some are objects, some are numbers, etc. and the caller would have to write code to combine them.

I would put money on progress being used in 95+% of cases to track I/O operations in order to show the user some sort of progress indicator. There are other uses, but I've rarely seen them. One example is wire.js, which could (but doesn't currently) track progress toward wiring completion, which involves wiring a discrete number of components. Another example is tracking the progress of UI wizard steps (I'm not convinced that's actually a good use case, but I've seen it).

With that in mind, what if progress values were required to be a number between 0 and 1, literally representing "percent complete". That seems to have some interesting properties:

  1. It's likely fairly easy to compute. For anything with discrete steps, it's steps accomplished / total steps. e.g. For I/O, it's bytes read / total bytes.
  2. It's easy to combine via averaging for operations where all promises must fulfill (eg when.all, when.map, when.reduce, etc etc). For 2 promises, combined = (progress1 + progress2) / 2, and by extension for N promises: combined = sum(progressValues) / progressValues.length. I believe this works for sequential, and "parallel" tasks.
    • It's also associative: progress2(a, progress2(b, c)) === progress2(progress2(a, b), c). which means that progress values from arbitrary operations (all, any, race) etc. can be combined easily, again via averaging: progress2(all(array1), p)
  3. There are other ways to combine:
    • when.any and when.race -> Math.max.apply(progressValues) (it's a race, so progress can be estimated by the one that appears to be winning)
    • when.some -> sort progress values in descending order, take top N, combine via average.
    • when.settle -> same as when.all?

I'm hoping that we can discuss here, and if this makes sense, talk to other promise library maintainers to get their thoughts as well.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions