-
-
Notifications
You must be signed in to change notification settings - Fork 938
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
Add progress events #322
Add progress events #322
Conversation
63d6189
to
7af37a0
Compare
3f4dd94
to
6fe4220
Compare
index.js
Outdated
transferred: uploaded, | ||
total: uploadBodySize | ||
}); | ||
}, 150); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we go with 150
? Can you move 150
into a variable with a descriptive name of why it's 150.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We just picked a random number for frequency of upload progress events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should definitely be clearer in the code then. 150 is very specific, wonder why we didn't just go with 100.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Np ;)
index.js
Outdated
} | ||
|
||
if (isFormData(body)) { | ||
body.getLength((err, size) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be nicer to use pify
here and on line 66, so we don't have to wrap the whole thing in the Promise constructor.
index.js
Outdated
getBodySize(opts) | ||
.then(size => { | ||
uploadBodySize = size; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the empty line here.
index.js
Outdated
|
||
promise.on = (name, fn) => { | ||
proxy.on(name, fn); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the empty line here.
index.js
Outdated
@@ -388,7 +568,7 @@ function got(url, opts) { | |||
} | |||
} | |||
|
|||
got.stream = (url, opts) => asStream(normalizeArguments(url, opts)); | |||
got.stream = (url, opts) => asStream(Object.assign({}, normalizeArguments(url, opts), {stream: true})); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be better to do the Object.assign
thing inside the asStream
function.
test/progress.js
Outdated
t.is(lastEvent.percent, 0); | ||
} | ||
|
||
events.forEach((event, index) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for (const [index, event] of events.entries()) {
test/progress.js
Outdated
.on('end', () => { | ||
checkEvents(t, events); | ||
t.end(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could use https://github.com/sindresorhus/get-stream here to be able to use async/await instead of test.cb
.
body.append('key', 'value'); | ||
body.append('file', file); | ||
|
||
const size = await pify(body.getLength.bind(body))(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pify
binds to the original object by default, so the bind here is moot I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, it fails without bind.
f0b3a3c
to
88fc78b
Compare
Thanks @sindresorhus, feedback addressed. Had to rebase and force push, because of a conflict. |
@vadimdemedes Thanks for the quick turn-around. |
Can you apply #322 (comment) to the other |
@sindresorhus Oh yeah, missed the other ones. |
@@ -202,6 +203,21 @@ got.stream('github.com') | |||
|
|||
`redirect` event to get the response object of a redirect. The second argument is options for the next request to the redirect location. | |||
|
|||
##### .on('uploadProgress', progress) | |||
##### .on('downloadProgress', progress) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should probably clarify that these can be used with the Promise
interface too. It's a little ambiguous now since they're documented under got.stream
.
@alextes @floatdrop I'll merge this on monday unless it gets any objections by then ;) |
const body = opts.body; | ||
|
||
if (opts.headers['content-length']) { | ||
return Number(opts.headers['content-length']); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just generally interested what the benefit is of wrapping this in a Number
object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not wrapping it in a Number object, it's coercing it to a number.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any benefit over parseInt? I never used Number directly so that's why I'm asking :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mostly just consistency. I also use Boolean() to coerce something to a Boolean. Same with String().
clearInterval(progressInterval); | ||
|
||
ee.emit('uploadProgress', { | ||
percent: 1, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is percent
set to 1? Probably missing something here :).
I'm also wondering why it is emitted? If some wants to calculate the percentage, he can easily do transferred / total
. I would rather not have it emitted, but that might just be me :).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is percent
emitted because total
can be null
when streaming?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is
percent
set to 1? Probably missing something here :).
It's calculating percent
to be from 0
to 1
. So 1
means it's the last upload progress event and it's done.
I'm also wondering why it is emitted?
Initially it was only for convenience. But there are also cases where total
can be unavailable (like you said, when streaming), so got makes sure that percent
is always available.
readme.md
Outdated
|
||
```js | ||
{ | ||
percent: 0.24, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
1024
bytes send against 10240
in total means 10% and thus percent
should be 0.1
.
@floatdrop @alextes Feel free to add your review still. I'm not gonna do a release yet. |
const headersSize = Buffer.byteLength(req._header); | ||
uploaded = req.connection.bytesWritten - headersSize; | ||
|
||
// Prevent the known issue of `bytesWritten` being larger than body size |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vadimdemedes if you have a link to an issue explaining what exactly is amiss and how simply ignoring any bytes uploaded beyond the body size is the right solution. Do share, I'd be happy to add it to the comment. If you don't let me know and I'll go looking myself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no explanation, I just observed this bug randomly and couldn't find a source of the issue.
}); | ||
|
||
req.connection.on('connect', () => { | ||
const uploadEventFrequency = 150; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just curious, is there a reason behind this number? 6 2/3 times a second?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason. It was just a guess on how to report progress events not too frequently, but still enough.
|
||
progressInterval = setInterval(() => { | ||
const lastUploaded = uploaded; | ||
const headersSize = Buffer.byteLength(req._header); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can header size change during upload? Otherwise, I don't see the point of putting this inside the interval or even the on 'connect'.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can't change during upload, but there's no way to know when headers are sent, is there? So I placed it here to correctly calculate the body size.
@sindresorhus haha, best times! I don't know why, but when I searched "sambucca" on Giphy, this is what it gave me, so now I'm posting this instead of my favorite drink to celebrate the merge: |
is there any plan to make a release with this change? |
Yes |
brings npm pkg from 0.75MB to 0.45MB after yarn autoclean --force, down to 0.25MB from this PR: sindresorhus#284 next big savings is removing progress, from sindresorhus#322
brings npm pkg from 0.75MB to 0.45MB after yarn autoclean --force, down to 0.25MB from this PR: sindresorhus#284 next big savings is removing progress, from sindresorhus#322
This PR adds upload and download progress events.
Initial upload/download progress event with
percent
equal to0
is always emitted. If it's not possible to retrieve the total upload/download body size,percent
andsize.total
are equal tonull
.Hack for receiving upload progress events when uploading buffers or strings
When sending
Buffer
asbody
, there are only 2uploadProgress
events, because the whole buffer gets written to the connection, soreq.connection.bytesWritten
becomes equal to buffer length. To work around this limitation and receive meaningful progress events,intoStream
module is used to convert buffer into stream.One more quirk. Since after conversion, there's no more access to buffer's size, I'm making it accessible by assigning it to
_buffer
on the stream here https://github.com/sindresorhus/got/pull/322/files#diff-168726dbe96b3ce427e7fedce31bb0bcR525 and getting it later again here https://github.com/sindresorhus/got/pull/322/files#diff-168726dbe96b3ce427e7fedce31bb0bcR76.TODO