unfetch
unfetch copied to clipboard
Code optimisations to headers calls
A few things to unpack here
As far as I can tell we only need the header keys, we don't actually need to construct the entries and headers objects with combined values, as the method on XMLHttpRequest getResponseHeader already does all that. It returns combined values and is case-insensitive. I guess the only risk would be if some older browser hasn't correctly implemented the original spec for it? Don't know if that's the reason you went this route.
Also according to spec header keys shouldn't contain duplicates. Ditto for header entries. So I'm checking before pushing new keys to the array
Directly using request.getResponseHeader for the header entries call and has and get checks. Kind of makes this difficult to mock/test as we're relying on the underlying XMLHttpRequest implementations.
Build "unfetch" to dist:
464 B: unfetch.js
464 B: unfetch.mjs
533 B: unfetch.umd.js
Build "unfetch" to polyfill:
466 B: index.js
ooooh you're so right! this is a great optimization.
Alright I think I found an issue with this approach:
getResponseHeader(key) is awesome because it gives us case-insensitive headers.{get,has}(), but it might cause problems with multiple headers of the same name:
// for an HTTP response like this:
// 200 OK
// Foo: one
// Foo: two
r.getResponseHeader('foo') === 'one, two'
In this case I'm not sure how we could feasibly separate the header values. The spec says they're always concatenated using ", ", but header values can contain that sequence of characters too.
@developit wondering why we would need to separate the values? The previous approach would return ['foo', 'foo'] for keys(), [['foo', 'one, two'],['foo', 'one, two']] for entries(), 'one, two' for the get() and true for the has(). This should do one better in not duping the entries or keys, but otherwise behave the same? Or am I missing something
@developit Actually I see the old way didn't combine the values for the entries mthod. That seems to be incorrect.
If you run the below code:
var h = new Headers()
h.append('Foo', 'bar')
h.append('Foo', 'baz')
var entries = [];
for (var i of h.entries()) {
entries.push(i)
}
console.log(entries) // => [['foo', 'bar, baz']]
I found this https://github.com/web-platform-tests/wpt/blob/6058e5f70f963efb34c56d4f882021601850e72d/fetch/api/headers/headers-combine.html
@developit I think the note here https://fetch.spec.whatwg.org/#headers-class is relevant
I've done a bit more research and previously there was a getAll() method which returned non combined name value pairs. This was removed from the spec and now all iterators and get() return the combined values. Only the set-cookie header actually causes problems, but since it's not exposed to the fetch response that was deemed acceptable. This has caused some issues for libraries like node-fetch, and they worked around it by using the non standard raw() method which returns combined values, but as an array.
https://github.com/bitinn/node-fetch/issues/251#issuecomment-287519538
Thanks for digging so deeply into this one! I think I was remembering the old .get() behavior, and forgot that concat was already what we return for get(). I think we're probably good to merge this.
One huge perk of the size drop you've managed here is that it gives us room to explore supporting Headers, Request and Response. There are some oddities associated with exporting these in the ponyfill version, but for the polyfill I think we might be able to fit them into the newfound 50b.
btw - I just spent a week around Cape Town. Nice place!
Glad to be able to contribute 😊
And thanks, I rather like it here too!
@developit let me know if you need me to do anything to move this along
Why was this never merged?
@RReverser because I'm a bad person!
Alrighty, I merged this manually (had to rewrite the history). Sorry for the (checks watch) 5 year delay!