-
-
Notifications
You must be signed in to change notification settings - Fork 42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better progress API by reporting both done and total values #1
Comments
I assume you're talking about How would |
No, this would change the progress reporting everywhere. Or maybe I don't understand the comment.
There is no The The code would explain this better I think, so here is a simplified difference between current and proposed solutions: // CURRENT
const progressFn = progress => {
this._progress = progress;
for (const listener of this._listeners) {
listener(progress);
}
}
// PROPOSED
const progressFn = (done, total) => {
this._done = done;
this._total = total;
for (const listener of this._listeners) {
listener(done, total);
}
} And here is the Notes:
// CURRENT
const sum = iterable => {
let total = 0;
for (const value of iterable.values()) total += value;
return total;
};
const progressMap = new Map();
const reportProgress = () => {
progress(sum(progressMap) / promises.length);
};
for (const promise of promisses) {
progressMap.set(promise, 0);
promise.onProgress(percentage => {
progressMap.set(promise, percentage);
reportProgress();
});
// please ignore await inside for-of loop, this is a pMapping
// function in the actual implementation
await promise;
progressMap.set(promise, 1);
reportProgress();
}
// PROPOSED
const sum = (iterable, prop) => {
let total = 0;
for (const value of iterable.values()) {
if (value[prop] === undefined) return undefined;
total += value[prop];
}
return total;
};
const progressMap = new Map();
const reportProgress = () => {
progress(sum(progressMap, 'done'), sum(progressMap, 'total'));
};
for (const promise of promisses) {
progressMap.set(promise, {done: 0, total: 1});
promise.onProgress((done, total) => {
progressMap.set(promise, {done, total});
reportProgress();
});
// please ignore await inside for-of loop, this is a pMapping
// function in the actual implementation
await promise;
const {done, total} = progressMap.get(promise);
if (done === 0 && total === 1) {
progressMap.set(promise, {done: 1, total: 1});
}
reportProgress();
}
Yes, my values in |
I may be a bit slow today but if What's your suggested API to know what const allProgressPromise = PProgress.all([
thisPromiseIs1kb(),
thisPromiseIs99kb(),
]);
(async () => {
allProgressPromise.onProgress(console.log);
//=> 1
//=> 100
await allProgressPromise;
})(); |
First of all, the If const allProgressPromise = PProgress.all([
thisPromiseIs1(), // always calls => progress(done, total)
thisPromiseIs99(), // always calls => progress(done, total)
]);
allProgressPromise.onProgress(console.log);
//=> 1, 100
//=> 2, 100
//=> ...
//=> 100, 100 In case any of them don't pass the total in each const allProgressPromise = PProgress.all([
thisPromiseIs1(), // always calls => progress(done, total)
thisPromiseIs99(), // always calls => progress(done)
]);
allProgressPromise.onProgress(console.log);
//=> 1, undefined
//=> 2, undefined
//=> ...
//=> 100, undefined In case they both have totals, and you add a raw const allProgressPromise = PProgress.all([
thisPromiseIs1(), // always calls => progress(done, total)
thisPromiseIs99(), // always calls => progress(done, total)
Promise.resolve(), // doesn't call, defaults to 0/1, and goes 1/1 on resolve
]);
allProgressPromise.onProgress(console.log);
//=> 1, 101
//=> 2, 101
//=> ...
//=> 101, 101 In case any of the PProgress promises report const allProgressPromise = PProgress.all([
thisPromiseIs1(), // always calls => progress(done, total)
thisPromiseIs99(), // always calls => progress(done)
Promise.resolve(), // doesn't call, defaults to 0/1, and goes 1/1 on resolve
]);
allProgressPromise.onProgress(console.log);
//=> 1, undefined
//=> 2, undefined
//=> ...
//=> 101, undefined I think this covers all possible cases for |
So the value of Also this makes the progress meaningless until all the totals are known. Look at your last example. What does |
I'd argue that if you are creating a PProgress instance, you have to call progress at least once before resolving, otherwise what is the point? But even if not, I see that current implementation is already forcing
How so? All promises default to 0/1, and if not updated before resolving update manually to 1/1, which is still a valid and usable progress state in all examples above.
It's absolutely not meaningless. That is one of the main points of this whole issue, to also provide a progress handling in cases where And if you just want to use PProgress with these changes as you were until now, all you have to do is just switch slash // before
progress(done / total);
promise.onProgress(progress => console.log(progress));
// after
progress(done, total);
promise.onProgress((done, total) => console.log(done / total)); All this proposal does is introduce a slight API change which gives move power, features, and options to both the progress implementors as well as the progress consumers. |
Sorry I ended up on this issue again 😅
It sounds to me that you just need a Promise that calls your callback, some sort of reporter. The only thing between you and your objective are the limitations that Lines 70 to 84 in a24163f
I see two solutions:
The whole module is setup in a way that |
All the arguments for my case are already written above. In summary, the current API is inaccurate, limited, and regarding indeterminate progress reporting impossible. I already forked this 2 years ago, so if you really don't see value in my proposal and are keeping this issue open just for me, feel free to close it.
That's what major bumps are for. |
I somehow managed to miss this discussion in 2017... @darsain Your arguments makes total sense. I just made If I had done const PProgress = require('p-progress');
const progressPromise = new PProgress((resolve, reject, progress) => {
const job = new Job();
// It's optional to set this.
progress.totalCount = job.getSize();
job.on('data', data => {
progress.completedCount += data.length;
});
job.on('finish', resolve);
job.on('error', reject);
});
(async () => {
progressPromise.onProgress(progress => {
console.log(progress);
/*
{
completedCount: 20,
totalCount: 100,
fractionCompleted: 0.2
}
*/
/*
If `totalCount` is not set, it and `fractionCompleted` would just be `0`.
`totalCount` can be set at any time inside `new PProgress`.
*/
});
await progressPromise;
})(); Just a quick braindump. The benefit of properties over methods is that they can also be read by the code inside And if you like the current behavior, you would still be able to do it by setting |
Yes, passing the data on an object is definitely a better idea, but can you please simplify the property names? At least dropping the Count suffix. I'd suffer writing the verbose ones from the example. 😄 |
Hah, sure. I initially had it as |
If |
@Richienb Correct |
Current implementation of forcing us to report the progress fraction has a lot of limitations:
totalSize
, but could still report the progress of how much data has been processed thus far.PProgress.all()
. Without p-progress, or callback consumers knowing the totals, each job is equal no matter how much data it is processing.I propose not enforcing the passing of fraction, but instead keeping track of both
done
andtotal
values, reporting them, and letting the user decide how to handle it. This will give us more options and data in our progress implementations.API:
The onProgress callback would than report these values in 1st and 2nd argument. If
total
isundefined
, the end is unknown and user can switch handling:In
PProgress.all().onProgress
callback, thedone
andtotal
values in onProgress callback will be the total additions of both of the values of all passes progress promisses. And if any of the promisses is missing thetotal
value, the resulting onProgress callback will also receiveundefined
astotal
, since we can no longer tell what the total of all promisses is now.Huge benefit of knowing about the total
total
inPProgress.all()
callback is a more accurate calculation of the whole progress. For example, if you have 2 jobs, one is processing 1KB, another is processing 99KB, and the 1st ends while the 2nd hasn't even started, you now have an accurate progress of0.01
, instead of0.5
. And if you do want it to report that0.5
, well you just do this in each job progress report:And now each job is equal no matter of the amount of data it's processing.
As you see, this kind of API would give us a lot more power, options, data, and ability to handle jobs with unknown totals in our implementations, while still remaining very simple.
The text was updated successfully, but these errors were encountered: