unfetch icon indicating copy to clipboard operation
unfetch copied to clipboard

Code optimisations to headers calls

Open simonbuerger opened this issue 7 years ago • 10 comments
trafficstars

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.

simonbuerger avatar Sep 20 '18 09:09 simonbuerger

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

simonbuerger avatar Sep 20 '18 09:09 simonbuerger

ooooh you're so right! this is a great optimization.

developit avatar Sep 20 '18 14:09 developit

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 avatar Sep 20 '18 14:09 developit

@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

simonbuerger avatar Sep 20 '18 15:09 simonbuerger

@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']]

simonbuerger avatar Sep 20 '18 15:09 simonbuerger

I found this https://github.com/web-platform-tests/wpt/blob/6058e5f70f963efb34c56d4f882021601850e72d/fetch/api/headers/headers-combine.html

simonbuerger avatar Sep 20 '18 15:09 simonbuerger

@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

simonbuerger avatar Sep 20 '18 20:09 simonbuerger

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!

developit avatar Oct 08 '18 19:10 developit

Glad to be able to contribute 😊

And thanks, I rather like it here too!

simonbuerger avatar Oct 09 '18 20:10 simonbuerger

@developit let me know if you need me to do anything to move this along

simonbuerger avatar Jan 15 '19 06:01 simonbuerger

Why was this never merged?

RReverser avatar Dec 12 '22 23:12 RReverser

@RReverser because I'm a bad person!

developit avatar Dec 30 '22 22:12 developit

Alrighty, I merged this manually (had to rewrite the history). Sorry for the (checks watch) 5 year delay!

developit avatar Dec 30 '22 23:12 developit