fetch() vs WebTransport

145 views
Skip to first unread message

guest271314

unread,
Sep 15, 2021, 10:15:41 AM9/15/21
to web-transport-dev

Why use WebTransport instead of fetch()?

 What are the advantages of using WebTransport instead of using fetch()?

Yutaka Hirano

unread,
Sep 15, 2021, 10:22:50 AM9/15/21
to guest271314, web-transport-dev
- Full duplex communication
- Datagrams

WebTransport has these whereas fetch doesn't.

On Wed, Sep 15, 2021 at 11:15 PM guest271314 <guest...@gmail.com> wrote:

Why use WebTransport instead of fetch()?

 What are the advantages of using WebTransport instead of using fetch()?

--
You received this message because you are subscribed to the Google Groups "web-transport-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to web-transport-...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/web-transport-dev/af907771-9043-42db-8b69-762195ba857bn%40chromium.org.

guest271314

unread,
Sep 15, 2021, 10:25:25 AM9/15/21
to web-transport-dev, yhi...@chromium.org, web-transport-dev, guest271314
At the front-end I cannot tell the difference between a datagram and non-datagram. fetch() is far more reliable than WebTransport from my perspective.

Can you include an example of a "Full duplex communication" that cannot be achieved with fetch()?

guest271314

unread,
Sep 15, 2021, 10:38:55 AM9/15/21
to web-transport-dev, guest271314, yhi...@chromium.org, web-transport-dev
From experimentation, I do not think there is any way to know when the WebTransport incoming readable stream is 'done'.

Yutaka Hirano

unread,
Sep 15, 2021, 11:10:54 AM9/15/21
to guest271314, web-transport-dev
We are not saying WebTransport is always better than fetch(). It is very possible that fetch() serves better for your use case.

Reg: full-duplex, with fetch(), you need to finish sending the request before starting receiving the response. With WebTransport, you can have a pair of readable and writable streams both of which are ready to use.

guest271314

unread,
Sep 15, 2021, 8:22:16 PM9/15/21
to web-transport-dev, yhi...@chromium.org, web-transport-dev, guest271314
> Reg: full-duplex, with fetch(), you need to finish sending the request before starting receiving the response. With WebTransport, you can have a pair of readable and writable streams both of which are ready to use.

Unfortunately, that is not the case. WebTransport (with aioquic) does not stream to client until internal process is complete, yet that never occurs and a timeout happens.

With fetch() I can do

fetch(url, {method:'post', body:<ReadableStrem|command as string>, signal:abortSignal})
  .then((r) => r.body.pipeTo(...))

in PHP

  stream_set_blocking($input = fopen("php://input", "r"), 0);
  passthru(stream_get_contents($input));

That blocks in WebTransport


                data = subprocess.run(split(input_data.decode()), stdout=subprocess.PIPE)           
                payload = data.stdout
                self._http._quic.send_stream_data(
                    response_id, payload, end_stream=True)
                self.stream_closed(event.stream_id)

Failed to establish a connection to https://localhost:4433/tts: net::ERR_QUIC_PROTOCOL_ERROR.QUIC_NETWORK_IDLE_TIMEOUT (No recent network activity after 3999895us. Timeout:4snum_undecryptable_packets: 0 {}).
TypeError: Connection lost.

Luke Curley

unread,
Sep 15, 2021, 9:00:55 PM9/15/21
to guest271314, web-transport-dev, yhi...@chromium.org
I'm also using WebTransport because it doesn't suffer from head-of-line blocking. I don't want packet loss for one stream impacting all other streams.

If you ignore datagrams, WebTransport versus WebSockets is more or less HTTP/3 versus HTTP/1. Some applications won't see an improvement at all, while other applications benefit the improved concurrency.

guest271314 if fetch works for your application, then I highly encourage you use it! Keep things simple until you need the additional functionality from an experimental network API.

guest271314

unread,
Sep 16, 2021, 12:45:52 AM9/16/21
to web-transport-dev, Luke Curley, web-transport-dev, yhi...@chromium.org, guest271314
I am interested in knowing why I can stream an indefinite response (in this case, live system audio output to headphones and speakers) with fetch() and PHP (and Native Messaging https://bugs.chromium.org/p/chromium/issues/detail?id=1189678#c50) but not with WebTransport https://bugs.chromium.org/p/chromium/issues/detail?id=1246152#c10, yet.

guest271314

unread,
Sep 19, 2021, 11:46:13 AM9/19/21
to web-transport-dev, guest271314, Luke Curley, web-transport-dev, yhi...@chromium.org
The issue of live streaming appears to be discussed at https://groups.google.com/a/chromium.org/g/web-transport-dev/c/wpSrznsMJJM and implemented using the deprecated QuicTransport at https://github.com/yuki-uchida/webcodecs_webtransport/blob/master/audio/quictransport_server.py. I am not sure how to use that code for the updated WebTransport - so that the server flushes and the (indefinite) stream does not timeout.

guest271314

unread,
Nov 13, 2021, 10:12:28 AM11/13/21
to web-transport-dev, Luke Curley, web-transport-dev, yhi...@chromium.org, guest271314
I have not yet been able to actually stream using WebTransport. I did when QuicTransport was operational. 

On Wednesday, September 15, 2021 at 6:00:55 PM UTC-7 Luke Curley wrote:

guest271314

unread,
Nov 14, 2021, 10:59:48 PM11/14/21
to web-transport-dev, guest271314, Luke Curley, web-transport-dev, yhi...@chromium.org
I have not yet been able to stream as i can with fetch() and PHP.

I have been able to compare a loop wherein 65536 datagrams are sent using GoogleChrome/samples webtransport_server.py and PHP passthru() calling Python script with same code.

    def h3_event_received(self, event: H3Event) -> None:
        print('h3_event', event)
        if isinstance(event, DatagramReceived):
            # payload = str(len(event.data)).encode('ascii')
            def read_chunks(): 
                for x in range(65536):
                    payload = ''.join(choice(digits) for i in range(32)).encode('utf8')
                    print(payload)
                    self._http.send_datagram(self._session_id, payload)
            read_chunks()

takes 58 seconds and the stream is never done

(async () => {
  var now = performance.now();
  const wt = new WebTransport('https://localhost:4433/counter');
  try {
    wt.onstatechange = (e) => console.log(e);
    await wt.ready;
    const writer = wt.datagrams.writable.getWriter();
    const data = new Uint8Array([0]);
    await writer.ready;
    await writer.write(data);
    await writer.close();
    let n = 0;
    let abortable = new AbortController;
    await wt.datagrams.readable.pipeThrough(new TextDecoderStream()).pipeTo(
      new WritableStream({
        write(value) {
          console.log(value, (performance.now() - now) / 1000, ++n);
        },
        close() {
          console.log('Stream closed.');
        },
      })
    , {signal: abortable.signal});
   
  } catch (err) {
     await wt.close();
    console.log('done');
    throw err;
  }
})().catch((err) => {
  console.error(err.message);
});

80560613475972544874688640627629 58.5455 65536

Using fetch() takes 3.8 seconds and the stream does complete.

#!/usr/bin/env -S python3 -u
import sys
from random import choice
from string import digits
'''
for chunk in iter(lambda: ''.join(choice(digits) for i in range(8)).encode('utf8'), b''):
  if chunk is not None:
      sys.stdout.buffer.write(chunk)
'''
def read_chunks(): 
    for x in range(65536):
        payload = ''.join(choice(digits) for i in range(32)).encode('utf8')
        sys.stdout.buffer.write(payload)
read_chunks()

var abortable = new AbortController();
var {signal} = abortable;
var now = performance.now();
fetch('http://localhost:8000/index.php', {method: 'post', body:'./stream.py', signal})
.then((r) => r.body)
.then((readable) => readable.pipeThrough(new TextDecoderStream()).pipeTo(new WritableStream({
  write(v) {console.log(v)},
  close() {console.log('Stream closed.')}
})).then(() => `Done streaming at ${(performance.now() - now) / 1000}.`))
.then(console.log)
.catch(console.warn);

Stream closed.
Done streaming at 3.8765999999642373.

If there is a means to actually stream using WebTransport, and the performance thereof such a method is more efficient than the 55 second lag of the code above using WebTransport kindly illuminate.
Reply all
Reply to author
Forward
0 new messages