Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Editorial review: Document WebSocketStream#35548

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
wbamberg merged 19 commits intomdn:mainfromchrisdavidmills:websocketstream
Sep 12, 2024

Conversation

@chrisdavidmills
Copy link
Contributor

Description

Chrome 124 supports theWebSocketStream API (see the associatedChromeStatus entry).

Note thatWebSocketStream is currently supported in Chromium-based browsers, and is not yet part of a standard so I will mark it as non-standard for now. Seewhatwg/websockets#48 for progress on that.

Motivation

Additional details

Related issues and pull requests

aFuzzyBear reacted with heart emoji
@chrisdavidmillschrisdavidmills requested review frompepelsbey andwbamberg and removed request fora teamAugust 22, 2024 09:00
@chrisdavidmillschrisdavidmills marked this pull request as draftAugust 22, 2024 09:01
@github-actionsgithub-actionsbot added Content:WebAPIWeb API docs size/m[PR only] 51-500 LoC changed labelsAug 22, 2024
@github-actions
Copy link
Contributor

github-actionsbot commentedAug 22, 2024
edited
Loading

Preview URLs (11 pages)
External URLs (17)

URL:/en-US/docs/Web/API/WebSocketStream
Title:WebSocketStream


URL:/en-US/docs/Web/API/WebSocketStream/WebSocketStream
Title:WebSocketStream: WebSocketStream() constructor


URL:/en-US/docs/Web/API/WebSocketStream/closed
Title:WebSocketStream: closed property


URL:/en-US/docs/Web/API/WebSocketStream/close
Title:WebSocketStream: close() method


URL:/en-US/docs/Web/API/WebSocketStream/url
Title:WebSocketStream: url property


URL:/en-US/docs/Web/API/WebSocketStream/opened
Title:WebSocketStream: opened property


URL:/en-US/docs/Web/API/WebSockets_API
Title:The WebSocket API (WebSockets)


URL:/en-US/docs/Web/API/CloseEvent/code
Title:CloseEvent: code property

(comment last updated: 2024-09-12 18:12:30)

@github-actionsgithub-actionsbot added size/l[PR only] 501-1000 LoC changed and removed size/m[PR only] 51-500 LoC changed labelsAug 23, 2024
@chrisdavidmillschrisdavidmills marked this pull request as ready for reviewAugust 23, 2024 07:19
Copy link
Contributor

@tomayactomayac left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is in a really good shape. Just some nits.

Maybe ping@ricea for a spec editor review.

chrisdavidmillsand others added11 commitsAugust 28, 2024 18:10
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
Co-authored-by: Thomas Steiner <tomac@google.com>
@chrisdavidmills
Copy link
ContributorAuthor

Thanks,@tomayac! I accepted all of your suggestions. I also checked and updated a few example snippets to usewss:// andself for feature detection to keep things consistent.

Also, because we need to specifyws:// in the code example for it to work as written, I've added a note into theWebSocketStream guide to draw the reader's attention to this, just in case they usewss:// and get stuck as a result.

I'm going to put this forward for editorial review now, but@ricea, feel free to have a look and make comments if you wish. It should take a little while for someone to pick it up, so there is time.

tomayac reacted with hooray emoji

@chrisdavidmillschrisdavidmills changed the titleDocument WebSocketStreamEditorial review: Document WebSocketStreamAug 28, 2024
Copy link
Collaborator

@wbambergwbamberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Here are comments on the non-reference pages.

Comment on lines 17 to 19
###WebSocketStream

The {{domxref("WebSocketStream")}} API is a modern reimagining of WebSocket client-side JavaScript functionality. It is promise-based, and therefore simpler to work with than the traditional {{domxref("WebSocket")}} API in the modern JavaScript scosystem. In addition, it uses the[Streams API](/en-US/docs/Web/API/Streams_API) to handle receiving and sending messages, meaning that socket connections can take advantage of stream[backpressure](/en-US/docs/Web/API/Streams_API/Concepts#backpressure) automatically, regulating the speed of reading or writing to avoid bottlenecks in the application. See[Using WebSocketStream to write a client](/en-US/docs/Web/API/WebSockets_API/Using_WebSocketStream) for more information.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think this needs more context. We have an intro about what websockets are, then go right into:

TheWebSocketStream API is a modern reimagining of WebSocket client-side JavaScript functionality. It is promise-based, and therefore simpler to work with than the traditionalWebSocket API ...

...but we haven't even talked about "traditional" WebSocket yet.

Also, "a modern reimagining of WebSocket client-side JavaScript functionality" reads like marketing to me. As a web developer who doesn't know yet about WebSockets, let alone Web Transport, what am I to make of all this?

IIUC there's a major drawback to WebSocketStream: it's nonstandard and only supported in one browser engine. Given that, I'm not sure MDN should recommend it above standard and cross-platform alternatives.

It would be very helpful here to lay out all the considerations, including Web Transport, in a neutral and factual way, to help developers make good choices.

It seems like the main motivation for WebSocketStream over WebSocket is to support backpressure, and I would put that first, before the "promise-based API" motivation (I doubt that would be a strong enough motivation alone for web developers to want to adopt this API). Theexplainer does a nice job of that actually.

So we might say something roughly like:

In the WebSocket API, there are two alternative ways to create and use web sockets: theWebSocket interface and theWebSocketStream interface.

  • TheWebSocket interface is stable and has good browser and server support. However it doesn't support backpressure (explain what this is and why it is a problem)
  • TheWebSocketStream is an alternative toWebSocket, that's based on the Streams API and therefore does support backpressure. However, it's nonstandard and has poor cross-browser support.

Additionally, the WebTransport API is expected to replace the WebSocket API for many applications, and supports backpressure along with many other features not supported by eitherWebSocket orWebSocketStream.something something about when and in which circs people should choose WebSocket over WebTransport or vice versa

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good call. In my next commit, I have used your suggested structure as a basis, and filled in the missing details.


{{DefaultAPISidebar("WebSockets API")}}{{non-standard_header}}

The {{domxref("WebSocketStream")}} API is a modern reimagining of WebSocket client-side JavaScript functionality. It is promise-based, and therefore simpler to work with than the traditional {{domxref("WebSocket")}} API in the modern JavaScript scosystem. In addition, it uses the[Streams API](/en-US/docs/Web/API/Streams_API) to handle receiving and sending messages, meaning that socket connections can take advantage of stream[backpressure](/en-US/docs/Web/API/Streams_API/Concepts#backpressure) automatically, regulating the speed of reading or writing to avoid bottlenecks in the application.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is a copy/paste from the overview page. I'm not sure it's needed here.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

The overview page no longer contains this paragraph. I have kept it on this page, but updated it to make it more concise and less marketing-y.


The {{domxref("WebSocketStream")}} API is a modern reimagining of WebSocket client-side JavaScript functionality. It is promise-based, and therefore simpler to work with than the traditional {{domxref("WebSocket")}} API in the modern JavaScript scosystem. In addition, it uses the[Streams API](/en-US/docs/Web/API/Streams_API) to handle receiving and sending messages, meaning that socket connections can take advantage of stream[backpressure](/en-US/docs/Web/API/Streams_API/Concepts#backpressure) automatically, regulating the speed of reading or writing to avoid bottlenecks in the application.

This article explains how to use the {{domxref("WebSocketStream")}} API to create a simple WebSocket client.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
This article explains how to use the {{domxref("WebSocketStream")}} API to create asimpleWebSocket client.
This article explains how to use the {{domxref("WebSocketStream")}} API to create a WebSocket client.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Argh, the curse of "simple"! Removed in next commit ;-)

Comment on lines 15 to 16
>[!NOTE]
>Backpressure is an issue with the traditional`WebSocket` API — it has no way to apply backpressure, therefore when messages arrive faster than the application can process them, the application will either fill up the device's memory by buffering those messages, become unresponsive due to 100% CPU usage, or both.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Also, this note seems out of place, especially if you remove or cut down the first para. What would be helpful, IMO, would be something about what (if anything) the developer has to do to take advantage of backpressure support. I think nothing? i.e. if they just don't read, then backpressure is exerted. Is that right though?

The page athttps://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Concepts#backpressure says:

To use backpressure in aReadableStream, we can ask the controller for the chunk size desired by the consumer by querying theReadableStreamDefaultController.desiredSize property on the controller. If it is too low, our ReadableStream can tell its underlying source to stop sending data, and we backpressure along the stream chain.

...which I don't really understand - who is "we" here?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I have removed the note from here, and put a shortened version on theWebSocket page.

In terms of how to use it, it is just automatic forWebSocketStream. I do say "automatically" in the opening paragraph. Do you think I need to be a bit more explicit?

It is somewhat out of scope for this PR to start updating the Streams API docs. We could do that in a separate PR. Maybe file an issue for now?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

In terms of how to use it, it is just automatic for WebSocketStream. I do say "automatically" in the opening paragraph. Do you think I need to be a bit more explicit?

Yes, I do. The doc links tohttps://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Concepts#backpressure, which as I say is hard to understand, but does not make it obvious that the developer has to do nothing for backpressure to work.

I think it would be best to spell this out in the bit about "To read data from the socket, you can continuously callReadableStreamDefaultReader.read() ...", and will leave a suggestion there.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

OK, cool. I've also added a little qualifier here in parens - "(no additional action required by the developer)" - which will hopefully help too.

To write data to the socket, you can use {{domxref("WritableStreamDefaultWriter.write()")}}:

```js
awaitwriter.write("My message");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Why await here?

Copy link
ContributorAuthor

@chrisdavidmillschrisdavidmillsSep 6, 2024
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I was just including it becausewrite() returns a promise. I guess I don't need it for this trivial line. Removed.

Comment on lines +198 to +200
wss.close({
code:1000,
reason:"That's all folks",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We say a few times that it's preferable to useabort(), maybe better to show that?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

We also say that close() is used when providing a custom code and/or reason. In this case we are providing a custom reason, so I think this is OK.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

To be pedantic, which I always am, it says "custom codeand reason".

chrisdavidmills reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

OK, all relevant instances now changed to "and/or".

<h2>WebSocketStream Test</h2>
<p>Sends a ping every five seconds</p>
<divid="output"></div>
<script>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I think it would be easier to read this if the JS were in an external script.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Possibly so, but this would also make it slightly more annoying for a user to copy and paste and chuck into a file for testing purposes. I think it is better to leave as-is, by this token.

slug:Web/API/WebSockets_API/Using_WebSocketStream
page-type:guide
status:
-non-standard
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

also experimental?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

OK, makes sense. I've also added it to theWebSocketStream interface pages.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

FWIW this should get added automatically from the BCD. But only in reference pages, not in guide pages.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Ah, OK. I keep forgetting what is automatically added and what isn't.

The main bulk of our code is contained within the`start()` function, which we define and then immediately invoke. We await the {{domxref("WebSocketStream.opened", "opened")}} promise, then after it fulfills write a message to let the reader know the connection is successful and create {{domxref("ReadableStreamDefaultReader")}} and {{domxref("WritableStreamDefaultWriter")}} instances from the returned`readable` and`writable` properties.

Next, we`write()` a`"ping"` value to the socket and communicate that to the user. At this point, the server will respond with a`"pong"` message. We await the`read()` of the read message, communicate it to the user, then write another`"ping"` to the server after a timeout of 5 seconds. This continues the`"ping"`/`"pong"` loop indefinitely.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
Next, we`write()` a`"ping"` value to the socket and communicate that to the user. At this point, the server will respond with a`"pong"` message. We await the`read()` of theread message, communicate it to the user, then write another`"ping"` to the server after a timeout of 5 seconds. This continues the`"ping"`/`"pong"` loop indefinitely.
Next, we`write()` a`"ping"` value to the socket and communicate that to the user. At this point, the server will respond with a`"pong"` message. We await the`read()` of thereasponse, communicate it to the user, then write another`"ping"` to the server after a timeout of 5 seconds. This continues the`"ping"`/`"pong"` loop indefinitely.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

updated

>[!NOTE]
>To get the example working, you'll also need a server component. We wrote our client to work along with the Deno server explained in[Writing a WebSocket server in JavaScript (Deno)](/en-US/docs/Web/API/WebSockets_API/Writing_a_WebSocket_server_in_JavaScript_Deno), but any compatible server will do.
First we grab a reference to a DOM element into which we will write output messages, and define a utility function that writes a message to it:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I'm a bit worried that this duplication of the code will make it hard to maintain. I understand though that just quoting the whole block then talking through it all might be indigestible, so idk what is for the best.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I appreciate that, but I've not got a better solution. Leaving as-is.

Copy link
Collaborator

@wbambergwbamberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Comments for the other pages.

-`options` {{optional_inline}}
- : An object than can contain the following properties:
-`protocols` {{optional_inline}}
- : An array of strings representing custom protocols to use for the connection.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Should we explain what this option is used for? Also, are there syntactic restrictions on the strings?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Added. Info on allowable names was hard to track down, and I didn't really find anything concrete about syntactic restrictions. I have added some more useful info.

wbamberg reacted with thumbs up emoji
Comment on lines 62 to 63
>[!NOTE]
>Alternatively, you can use the {{domxref("WebSocketStream.close()")}} method to close a connection, however this is mainly needed if you wish to specify a custom code and reason for the server to report.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Don't think this should be a note. It works fine as a normal paragraph.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Agreed. I've de-noted it.

-`url`
- : A string representing the URL of the WebSocket server you want to connect to with this`WebSocketStream` instance. Allowed URL schemes are`"ws"`,`"wss"`,`"http"`, and`"https"`.
-`options` {{optional_inline}}
- : An object than can contain the following properties:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
- : An objectthan can contain the following properties:
- : An objectthat can contain the following properties:

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

fixed - ta!

##Syntax

```js-nolint
new WebSocketStream(url, options)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
new WebSocketStream(url, options)
new WebSocketStream(url)
new WebSocketStream(url, options)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good call; updated.

Comment on lines 16 to 17
>[!NOTE]
>An alternative mechanism for closing a`WebSocketStream` is to specify an {{domxref("AbortSignal")}} in the[`signal`](/en-US/docs/Web/API/WebSocketStream/WebSocketStream#signal) option of the constructor upon creation. The associated {{domxref("AbortController")}} can then be used to close the WebSocket connection. This is generally the preferred mechanism, however`close()` can be used if you wish to specify a custom code and reason for the server to report.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Again I don't think this is a note.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Again, de-noted.

- {{domxref("WebSocketStream.url", "url")}} {{ReadOnlyInline}}
- : Returns the URL of the WebSocket server that the`WebSocketStream` instance was created with.
- {{domxref("WebSocketStream.closed", "closed")}} {{ReadOnlyInline}}
- : Returns a {{jsxref("Promise")}} that fulfills with an object once the socket connection is closed. The object contains the closing code and reason sent by the server.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

re "sent by the server", same comment as in theclosed page, what if the client closes it?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Same answer as above. I'm not sure if this needs an update. I have modified it slightly, to "as sent by the server"

- {{domxref("WebSocketStream.closed", "closed")}} {{ReadOnlyInline}}
- : Returns a {{jsxref("Promise")}} that fulfills with an object once the socket connection is closed. The object contains the closing code and reason sent by the server.
- {{domxref("WebSocketStream.opened", "opened")}} {{ReadOnlyInline}}
- : Returns a {{jsxref("Promise")}} that fulfills with an object once the socket connection is successfully opened. The object contains several useful features, including a {{domxref("ReadableStream")}} and a {{domxref("WritableStream")}} instance for receiving and sending data on the connection.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
- : Returns a {{jsxref("Promise")}} that fulfills with an object once the socket connection is successfully opened.The object contains several useful features, including a {{domxref("ReadableStream")}} and a {{domxref("WritableStream")}} instance for receiving and sending data on the connection.
- : Returns a {{jsxref("Promise")}} that fulfills with an object once the socket connection is successfully opened.Among other properties, the object includes a {{domxref("ReadableStream")}} and a {{domxref("WritableStream")}} instance for receiving and sending data on the connection.

Very picky. "several useful features" seems a bit odd. Should it be taken for granted that the properties are useful?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Yup, very picky. You are right too, which is even more annoying ;-)

I have updated the wording to "Among other features, this object contains a...", as the items listed aren't the actual property names, but the values they contain.

{{APIRef("WebSockets API")}}{{non-standard_header}}

The**`opened`** read-only property of the
{{domxref("WebSocketStream")}} interface returns a {{jsxref("Promise")}} that fulfills with an object once the socket connection is successfully opened. The object contains several useful features, including a {{domxref("ReadableStream")}} and a {{domxref("WritableStream")}} instance for receiving and sending data on the connection.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

"several useful features" again.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Same change made here.

-`extensions`
- : A string representing any extensions applied to the`WebSocketStream`. Such extensions are not currently defined, but may be in the future. Currently returns an empty string.
-`protocol`
- : A string representing any custom protocol used to open the current WebSocket connection, as specified in the[`protocols`](/en-US/docs/Web/API/WebSocketStream/WebSocketStream#protocols) option of the`WebSocketStream()` constructor. Returns an empty string if no custom protocol was used.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I guess this must be one of the ones given in the constructor?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I don't really understand the question. The text clearly says "as specified in theprotocols option of theWebSocketStream() constructor".

I've updated the end of the description to "if no custom protocol was set during instantiation", in case it is useful.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I don't think "as specified in..." is very clear.protocols is an array, this is a single item. I'm assuming what happens is that the client passes, inprotocols, an array of custom protocols it is prepared to work with, and the server responds with a single protocol from the array. But the docs don't say this, so I have to guess.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Ah, OK, I getcha now. I've done a bit of reading around this, and have updated this description to:

A string representing the sub-protocol used to open the current WebSocket connection (chosen from the options specified in theprotocols option of theWebSocketStream() constructor). Returns an empty string if no sub-protocol has been used to open the connection (i.e. no sub-protocol options were included in the constructor call).

##Examples

```js
constoutput=document.querySelector("#output");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

As for closed, I think a smaller more focused example would be better.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I've cut it down quite a bit, but not as much as theclosed example.


{{DefaultAPISidebar("WebSockets API")}}

The**WebSocket API** is an advanced technology that makes it possible to open a two-way interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
The**WebSocket API**is an advanced technology thatmakes it possible to open a two-way interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply.
The**WebSocket API** makes it possible to open a two-way interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive responses without having to poll the server for a reply.

(not necessarily event-driven)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Sounds reasonable. Updated to use your wording.

- The`WebSocketStream` is a {{jsxref("Promise")}}-based alternative to`WebSocket`. It uses the[Streams API](/en-US/docs/Web/API/Streams_API) to handle receiving and sending messages, meaning that socket connections can take advantage of stream backpressure automatically, regulating the speed of reading or writing to avoid bottlenecks in the application. However,`WebSocketSteam` is non-standard and currently only supported in one rendering engine.

Additionally, the[WebTransport API](/en-US/docs/Web/API/WebTransport_API) is expected to replace the WebSocket API for many applications. WebTransport is a versatile, low-level API that provides backpressure and many other features not supported by either`WebSocket` or`WebSocketStream`, such as unidirectional streams, out-of-order delivery, and unreliable data transmission via datagrams. WebTransport is more complex to use than WebSockets and its cross-browser support is not as wide, but it enables the implementation of sophisticated solutions. If standard WebSocket connections are a good fit for your use case and you need wide browser compatibility, you should employ the WebSockets API to get up and running quickly. However, if your application requires a non-standard custom solution, then you should use the WebTransport API.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thank you, I like this a lot better.

chrisdavidmills reacted with thumbs up emoji
>[!NOTE]
>To get the example working, you'll also need a server component. We wrote our client to work along with the Deno server explained in[Writing a WebSocket server in JavaScript (Deno)](/en-US/docs/Web/API/WebSockets_API/Writing_a_WebSocket_server_in_JavaScript_Deno), but any compatible server will do.
The HTML for the demo is as follows. It includes informational {{htmlelment("h1")}} and {{htmlelment("h1")}} elements, a {{htmlelment("button")}} to close the WebSocket connection that is initially disabled, and a {{htmlelment("div")}} for us to write output messages into.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Suggested change
The HTML for the demo is as follows. It includes informational {{htmlelment("h1")}} and {{htmlelment("h1")}} elements, a {{htmlelment("button")}} to close the WebSocket connection that is initially disabled, and a {{htmlelment("div")}} for us to write output messages into.
The HTML for the demo is as follows. It includes informational {{htmlelement("Heading_Elements", "h2")}} and {{htmlelement("p")}} elements, a {{htmlelement("button")}} to close the WebSocket connection that is initially disabled, and a {{htmlelement("div")}} for us to write output messages into.

(please double check the syntax for the H2)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Oh darn, thanks for the fixes there.

The syntax worked, but I ended up replacing the h2 macro call with a regular link, as for some reason the link was not showing the angle brackets or in code font.

Comment on lines 15 to 16
>[!NOTE]
>Backpressure is an issue with the traditional`WebSocket` API — it has no way to apply backpressure, therefore when messages arrive faster than the application can process them, the application will either fill up the device's memory by buffering those messages, become unresponsive due to 100% CPU usage, or both.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

In terms of how to use it, it is just automatic for WebSocketStream. I do say "automatically" in the opening paragraph. Do you think I need to be a bit more explicit?

Yes, I do. The doc links tohttps://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Concepts#backpressure, which as I say is hard to understand, but does not make it obvious that the developer has to do nothing for backpressure to work.

I think it would be best to spell this out in the bit about "To read data from the socket, you can continuously callReadableStreamDefaultReader.read() ...", and will leave a suggestion there.

Comment on lines +65 to +77
To read data from the socket, you can continuously call {{domxref("ReadableStreamDefaultReader.read()")}} until the stream has finished, which is indicated by`done` being`true`:

```js
while (true) {
const {value,done }=awaitreader.read();
if (done) {
break;
}

// Process value in some way
}
```

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Here I think is where we should spell out the backpressure thing. Perhaps something like:

Suggested change
To read data from the socket, you can continuously call {{domxref("ReadableStreamDefaultReader.read()")}} until the stream has finished, which is indicated by`done` being`true`:
```js
while (true) {
const { value, done } = await reader.read();
if (done) {
break;
}
// Process value in some way
}
```
To read data from the socket, you can continuously call {{domxref("ReadableStreamDefaultReader.read()")}} until the stream has finished, which is indicated by`done` being`true`:
```js
while (true) {
const { value, done } = await reader.read();
if (done) {
break;
}
// Process value in some way
}
```
Note that the client can control the rate at which it receives data by calling`read()` only when it is ready: if data is arriving faster than the client can read it, the underlying Streams API automatically exerts backpressure on the sender.

(assuming that is true!)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I don't think the point whenread() is called has anything to do with backpressure. This is not automatic, but a choice made by the developer in the code?

I've read around this subject a bit, and added the following paragraph after the code snippet:

The browser automatically controls the rate at which the client receives and sends data by applying backpressure when needed. If data is arriving faster than the client canread() it, the underlying Streams API exerts backpressure on the server. In addition,write() operations will only proceed if it is safe to do so.

constreader=readable.getReader();
constwriter=writable.getWriter();

awaitwriter.write("ping");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

You don't have to await to make it work: await just ensures that the promise fulfills before it executes the next line.

I mean, usually I seeawait being used if you want to make your code behave like synchronous code, for instance if it's returning something you need in the next line:

constresponse=awaitfetch(url);constdata=awaitresponse.json();

(or as we are doing withread(), where we need the read value in the next line).

But in this case we're not, so what's functionally the difference between awaiting and not awaiting, except that we're imposing an ordering when we maybe don't need to.

I suppose awaiting means we can reportwriteToScreen("SENT: ping");, because we knowwrite() didn't reject, although it's not clear whether not rejecting actually means we sent it, ashttps://developer.mozilla.org/en-US/docs/Web/API/WritableStreamDefaultWriter/write says:

Note that what "success" means is up to the underlying sink; it might indicate that the chunk has been accepted, and not necessarily that it is safely saved to its ultimate destination.

But then if that is the reason, isn't it better to use try/catch so we can report an error?

So it could say:

try{awaitwriter.write("ping");writeToScreen("SENT: ping");}catch(e){writeToScreen(`Error writing to socket:${e.message}`);}

...and then there's a use forawait.

Ah, maybe it's not worth worrying about.

slug:Web/API/WebSockets_API/Using_WebSocketStream
page-type:guide
status:
-non-standard
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

FWIW this should get added automatically from the BCD. But only in reference pages, not in guide pages.

reason:"That's all folks",
});
closeBtn.disabled=false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

true?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Good call; updated.

Comment on lines +198 to +200
wss.close({
code:1000,
reason:"That's all folks",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

To be pedantic, which I always am, it says "custom codeand reason".

chrisdavidmills reacted with thumbs up emoji
Copy link
Collaborator

@wbambergwbamberg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

👍 thanks Chris!

@wbambergwbamberg merged commitf56df7c intomdn:mainSep 12, 2024
@chrisdavidmillschrisdavidmills deleted the websocketstream branchSeptember 13, 2024 07:07
@chrisdavidmills
Copy link
ContributorAuthor

👍 thanks Chris!

Likewise, thanks so much for the review Will!

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

@wbambergwbambergwbamberg approved these changes

@pepelsbeypepelsbeyAwaiting requested review from pepelsbeypepelsbey was automatically assigned from mdn/core-yari-content

+1 more reviewer

@tomayactomayactomayac left review comments

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

Content:WebAPIWeb API docssize/l[PR only] 501-1000 LoC changed

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

3 participants

@chrisdavidmills@tomayac@wbamberg

[8]ページ先頭

©2009-2025 Movatter.jp