-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
[WIP] Response now accepts ReadableStream as body #404
Conversation
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.
Thanks, this looks like a good start! Will users of streaming need any polyfills to be able to make use of this? Can you show off some example usage scenario in code?
package.json
Outdated
@@ -6,7 +6,7 @@ | |||
"repository": "github/fetch", | |||
"license": "MIT", | |||
"devDependencies": { | |||
"bower": "1.3.8", | |||
"bower": "^1.7.9", |
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 this change necessary?
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.
Maybe not. But I got a warning saying one of Bowers depends was deprecated
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.
Deprecation warnings are fine. They don't affect us at all.
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.
Please undo the commit that made the change to bower version. It doesn't belong in this PR and was never necessary. As I said, deprecation warnings are acceptable.
fetch.js
Outdated
return reader.read().then(function(result){ | ||
if(!result.done){ | ||
chunks.push(result.value) | ||
return pump() |
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 it possible to create a while
loop rather than recursion? I guess not, because of async.
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.
Don't think so
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.
This is just for turning a stream into a blob/text/arraybuffer
We don't know in advance if they want a stream/blob/text or a arraybuffer. So I thought the best default responseType should be ms-stream or moz-chunked-arraybuffer instead of blob so we build all our Response method based on streams first
fetch.js
Outdated
var pump = function(){ | ||
return reader.read().then(function(result){ | ||
if(!result.done){ | ||
chunks.push(result.value) |
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.
Doesn't it defeat the point of streaming if we've just read the entire response into memory at once?
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.
Mm, no? You call blob, text or arraybuffer so you need to acembly all the chunks into one result.
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.
Fair point!
They need web-stream-polyfill if they want to use streams. ATM it's like an optional dependency.
Can show some example tomorrow. Just realized ’_bodyStream’ should just be named ’body’ to follow the spec |
@@ -177,6 +177,8 @@ | |||
this._bodyText = body.toString() | |||
} else if (!body) { | |||
this._bodyText = '' | |||
} else if (body.getReader) { | |||
this.body = 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.
Are we now allowing people to interface with response.body
directly? Is this in the spec?
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.
Yep, body is suppose to be a ReadableStream. You can test this directly in chrome's console log
res = new Response(new ReadableStream({}))
reader = res.body.getReader()
console.log(reader)
// even this works:
res = new Response(new Blob([]))
reader = res.body.getReader()
console.log(reader)
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 also suppose to solve abortable request by calling res.body.cancel()
So literally every thing you pass into new Response
should be transformed to ReadableStream IMO.
But I don't want to rush into things and change the hole polyfill
fetch.js
Outdated
var pump = function(){ | ||
return reader.read().then(function(result){ | ||
if(!result.done){ | ||
chunks.push(result.value) |
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.
Fair point!
package.json
Outdated
@@ -6,7 +6,7 @@ | |||
"repository": "github/fetch", | |||
"license": "MIT", | |||
"devDependencies": { | |||
"bower": "1.3.8", | |||
"bower": "^1.7.9", |
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.
Deprecation warnings are fine. They don't affect us at all.
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.
Thanks, this looks pretty good! One final thing we would need is tests for this. It's fine if the test suite imports a polyfill for streams. Ideally these tests would work in PhantomJS as well as a real browser.
fetch.js
Outdated
@@ -204,6 +206,21 @@ | |||
|
|||
if (this._bodyBlob) { | |||
return Promise.resolve(this._bodyBlob) | |||
} else if (this.body) { | |||
var reader = this.body.getReader(); |
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.
Minor: we don't use semicolons
fetch.js
Outdated
} else if (this.body) { | ||
var reader = this.body.getReader(); | ||
var chunks = []; | ||
var pump = function(){ |
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.
Minor: we usually put a space in between )
and {
(same applies to next line)
fetch.js
Outdated
var chunks = []; | ||
var pump = function(){ | ||
return reader.read().then(function(result){ | ||
if(!result.done){ |
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.
Minor: we usually put a space after if
fetch.js
Outdated
@@ -216,6 +233,10 @@ | |||
} | |||
|
|||
this.text = function() { | |||
if (this.body) { | |||
return this.blob().then(readBlobAsText) |
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 have some checks in place (see consumed()
below) to prevent reading the body data multiple times. Should the same restrictions also apply to readable streams?
Will try to add some test and fix the minor issues. |
Just discovered this: rs = new ReadableStream()
res = new Response(rs)
reader = res.body.getReader()
console.log(res.bodyUsed) // false
reader.read()
console.log(res.bodyUsed) // true |
Think I'm going to need a little bit of help with the test. Got a error: |
Not sure what that error is about, but PhantomJS is definitely going to need some ES shims before it can load the streams polyfill. PhantomJS has neither Symbol nor Object.assign support. Your test, however, runs but fails in Chrome with a different error. Perhaps you should work on making the test work in a real browser, and we can handle eventually getting it to run in PhantomJS. |
@jimmywarting Here are my polyfills for PhantomJS. It still fails with a cryptic exception that's different than yours. |
Works in the browser now... |
Weird, running
even the browser succeeded EDIT script don't exit properly I know Node runs until all event queues are empty could something like this be the cause? |
Do you have any idea how to tackle this? The test passes in browser but not in phantomjs |
Not sure. We could just exclude this test from PhantomJS then. But that's a shame, since this test won't ever get exercised in CI, and we risk this functionality falling out of date during future changes. |
This looks good to me now... |
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 are several reasons why I feel this PR is not ready for merge yet, in addition to my individual comments below:
- It adds the
response.body
property conditionally, meaning it won't be present unless the response is streamable. I have to check the spec about this, but I kind of feel that this property should always be available. - The tests are currently not confirming that the behavior is indeed streaming, just that
response.body
was present. Can we add something that asserts that we can use the streaming functionality?
fetch.js
Outdated
@@ -177,6 +194,14 @@ | |||
this._bodyText = body.toString() | |||
} else if (!body) { | |||
this._bodyText = '' | |||
} else if (body.getReader) { | |||
this.body = body | |||
Object.defineProperty(this, 'bodyUsed', { |
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.
I'm not a fan of the more complex bodyUsed
implementation, but I guess if the value of this property needs to be dependent on the status of body
, and body
object can be accessed and manipulated directly, then we can't avoid having the dynamic accessor. 🤔
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.
I wasn't a big fan of this either, I even asked the community if it was okey to do this: whatwg/fetch#396
But it wasn't... We should maybe implement a new TypeError message that checks the locked property.
It's a bit more complicated to set the bodyUsed property since it needs set it upon the first getReader().read call and spying on this is not that easy...
var clone | ||
|
||
if (this.bodyUsed) { | ||
throw new TypeError('Failed to execute \'clone\' on \'Response\': Response body is already used') |
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.
If you used double quotes for the string, you wouldn't have to escape every single quote inside the string
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.
I used it first but then the linter complained about using 2 different quotes...
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.
Could as well fall thought and use tee()'s error message that already checks if stream is locked
test/test-worker.html
Outdated
@@ -8,6 +8,8 @@ | |||
<body> | |||
<div id="mocha"></div> | |||
<script src="/node_modules/url-search-params/build/url-search-params.js"></script> | |||
<script src="/test/es6-shims.js"></script> |
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 can remove the commits that add es6-shims since that was intended for PhantomJS and we couldn't make it run in the end anyway
// Firefox & Edge partially support fetch (but don't have stream support) | ||
// However the polyfilled Response do support it (With web-streams-polyfill) | ||
// PhantomJS can use the polyfill but failes togheter with mocha | ||
featureDependent(test, !isPhantomJS && support.stream, 'Response should accept ReadableStream', function() { |
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.
Instead of doing two separate checks !isPhantomJS && support.stream
, support.stream
should be false in the first place if the browser is PhantomJS. That simplifies this check.
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.
done
package.json
Outdated
@@ -6,7 +6,7 @@ | |||
"repository": "github/fetch", | |||
"license": "MIT", | |||
"devDependencies": { | |||
"bower": "1.3.8", | |||
"bower": "^1.7.9", |
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.
Please undo the commit that made the change to bower version. It doesn't belong in this PR and was never necessary. As I said, deprecation warnings are acceptable.
I would like Maybe we could implement some super-duper simple ReadableStream class that adds the minimal requirements with The logic around res.arrayBuffer(), res.blob() & res.text() could be implemented way more simpler if everything where built on top of ReadableStream (that is what i like most about jonnyreeves version that he is starting of from ReadableStream) |
@mislav any chances to see this changes in |
@eko24 Not at the present moment. I'm mostly away from my computer around the New Year and I have to re-review this once I get back. We definitely want to support this, but I need to study the spec around this myself and see if we can minimize the diff further. The soonest I might be able to get back to this is 2 weeks from now. |
Ok, thank you for update !
вт, 27 дек. 2016 г. в 16:48, Mislav Marohnić <notifications@github.com>:
… @eko24 <https://github.com/eko24> Not at the present moment. I'm mostly
away from my computer around the New Year and I have to re-review this once
I get back. We definitely want to support this, but I need to study the
spec around this myself and see if we can minimize the diff further. The
soonest I might be able to get back to this is 2 weeks from now.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#404 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAuRAca-7o-g3BtqcpKbO1miHdNSM9x7ks5rMSUygaJpZM4KPVQq>
.
|
Update dependencies to enable Greenkeeper 🌴
hello! |
…-1.1.0 chore(package): update url-search-params to version 1.1.0
@jimmywarting Thank you for your contribution and sorry that we have never reached a resolution regarding this! I have felt uneasy about all the code added to support this feature, which might prove to be tricky to maintain in the future and also I don't really see it being widely used. I'm calling this polyfill basically feature-frozen now #198 (comment) |
roger that |
This is a part necessary to be able to start supporting streaming response (#198)
here is just an example of how to use it
This PR don't make use of ReadableStream it just allows end user to be able to construct a Response with a ReadableStream as body as you should be able to do