Stosuj wsteczne obciążenie, aby zapobiec zasypaniu aplikacji komunikatami WebSocket przez zasypanie jej wiadomościami przez serwer WebSocket.
Tło
Interfejs API WebSocket
Interfejs WebSocket API udostępnia interfejs JavaScript dla protokołu WebSocket, co pozwala rozpocząć dwukierunkową interaktywną sesję komunikacji między przeglądarką użytkownika a serwerem. Za pomocą tego interfejsu API możesz wysyłać wiadomości do serwera i otrzymywać odpowiedzi oparte na zdarzeniach bez odpytywania serwera w poszukiwaniu odpowiedzi.
Streams API
Streams API umożliwia programowi JavaScript dostęp do strumieni danych odbieranych przez sieć i przetwarzać je zgodnie z potrzebami. Ważną kwestią w kontekście strumieni backpressure. Jest to proces, w którym pojedynczy strumień lub łańcuch rur reguluje szybkość czytania lub pisania. Gdy strumień lub strumień później w łańcuchu potoków jest nadal zajęty i nie jest gotowy na przyjmowanie kolejnych fragmentów, wysyła sygnał wstecz przez łańcuch, aby odpowiednio spowolnić dostarczanie.
Problem z bieżącym interfejsem WebSocket API
Nie można zastosować wstecznego obciążenia do odebranych wiadomości
W obecnym interfejsie WebSocket API reagowanie na wiadomość odbywa się
WebSocket.onmessage
funkcja EventHandler
jest wywoływana po odebraniu wiadomości z serwera.
Załóżmy, że mamy aplikację, która musi wykonywać intensywne operacje crunchingu danych
za każdym razem, gdy odebrana jest nowa wiadomość.
Skonfigurujesz proces podobny do poniższego kodu,
a ponieważ await
wynik rozmowy w usłudze process()
to nie problem, prawda?
// A heavy data crunching operation.
const process = async (data) => {
return new Promise((resolve) => {
window.setTimeout(() => {
console.log('WebSocket message processed:', data);
return resolve('done');
}, 1000);
});
};
webSocket.onmessage = async (event) => {
const data = event.data;
// Await the result of the processing step in the message handler.
await process(data);
};
Błąd! Problem z obecnym interfejsem WebSocket API polega na tym, że nie można zastosować obciążenia wstecznego.
Gdy wiadomości przychodzą szybciej, niż metoda process()
jest w stanie je obsłużyć,
proces renderowania zapełnia pamięć, buforując te wiadomości.
przestały reagować z powodu wykorzystania procesora w 100% lub obu tych przypadków.
Stosowanie prepresji wstecznej do wysyłanych wiadomości nie jest ergonomiczne
Zastosowanie wstecznego obciążenia do wysyłanych wiadomości jest możliwe, ale obejmuje odpytywanie
WebSocket.bufferedAmount
która jest niewydajna i nieergonomiczna.
Ta usługa tylko do odczytu zwraca liczbę bajtów danych, które zostały umieszczone w kolejce
używa połączeń z
WebSocket.send()
ale jeszcze nie są przesyłane do sieci.
Po przesłaniu wszystkich danych znajdujących się w kolejce ta wartość jest resetowana do zera.
ale jeśli będziesz nadal dzwonić pod numer WebSocket.send()
,
ale nadal będzie się wspinać.
Co to jest interfejs API WebSocketStream?
Interfejs WebSocketStream API rozwiązuje problem nieistniejącego lub nieergonomicznego wstecznego obciążenia przez integrację strumieni z interfejsem WebSocket API. Oznacza to, że możesz je zastosować „bezpłatnie” bez dodatkowych kosztów.
Sugerowane przypadki użycia interfejsu WebSocketStream API
Oto przykłady witryn, które mogą korzystać z tego interfejsu API:
- Aplikacje WebSocket o dużej przepustowości, które muszą zachowywać interaktywność, w konkretnym filmie i przy udostępnianiu ekranu.
- Podobnie jest w przypadku nagrywania filmów i innych aplikacji, które generują dużo danych w przeglądarce. który musi zostać przesłany na serwer. Dzięki ciśnieniu wstecznemu klient może przestać generować dane, zamiast zbierać je w pamięci.
Obecny stan,
Krok | Stan |
---|---|
1. Utwórz wyjaśnienie | Zakończono |
2. Utwórz początkową wersję roboczą specyfikacji | W toku |
3. Zbieraj opinie iterować projekt | W toku |
4. Wersja próbna origin | Zakończono |
5. Uruchom | Nie rozpoczęto |
Jak używać interfejsu WebSocketStream API
Przykład wprowadzający
Interfejs WebSocketStream API opiera się na obietnicach, dzięki czemu radzenie sobie z nim jest naturalne.
we współczesnym świecie JavaScriptu.
Zacznij od utworzenia nowego WebSocketStream
i przekaż mu adres URL serwera WebSocket.
Następnie zaczekaj, aż połączenie będzie opened
,
co daje
ReadableStream
.
lub
WritableStream
Wywołując funkcję
ReadableStream.getReader()
otrzymasz w końcu
ReadableStreamDefaultReader
,
co możesz następnie read()
danych od chwili zakończenia strumienia, czyli do momentu zwrócenia obiektu
{value: undefined, done: true}
.
W związku z tym, wywołując
WritableStream.getWriter()
otrzymasz w końcu
WritableStreamDefaultWriter
,
co możesz następnie write()
.
const wss = new WebSocketStream(WSS_URL);
const {readable, writable} = await wss.opened;
const reader = readable.getReader();
const writer = writable.getWriter();
while (true) {
const {value, done} = await reader.read();
if (done) {
break;
}
const result = await process(value);
await writer.write(result);
}
Ciśnienie wsteczne
A co z obiecaną funkcją sprężenia wstecznego?
Jak wspomnieliśmy powyżej, dostęp jest udostępniany „bezpłatnie”, bez konieczności wykonywania dodatkowych czynności.
Jeśli process()
potrzebuje więcej czasu, następna wiadomość zostanie wykorzystana dopiero wtedy, gdy potok będzie gotowy.
Podobnie WritableStreamDefaultWriter.write()
zostanie przeprowadzony tylko wtedy, gdy można to bezpiecznie zrobić.
Przykłady zaawansowane
Drugi argument w WebSocketStream to pakiet opcji umożliwiających przedłużenie dostępu w przyszłości.
Obecnie jedyną opcją jest protocols
,
który działa tak samo jak
drugi argument konstruktora WebSocket:
const chatWSS = new WebSocketStream(CHAT_URL, {protocols: ['chat', 'chatv2']});
const {protocol} = await chatWSS.opened;
Wybrane słowa kluczowe protocol
oraz potencjalne extensions
są częścią słownika
dostępne w ramach obietnicy WebSocketStream.opened
.
Wszystkie informacje o transmisji na żywo pochodzą z tego obietnicy,
ponieważ nie ma znaczenia w przypadku niepowodzenia połączenia.
const {readable, writable, protocol, extensions} = await chatWSS.opened;
Informacje o zamkniętym połączeniu WebSocketStream
Informacje, które były dostępne w
WebSocket.onclose
i
WebSocket.onerror
wydarzenia
w interfejsie WebSocket API jest teraz dostępna w ramach obietnicy WebSocketStream.closed
.
Obietnica jest odrzucana w przypadku brudnego zamknięcia transakcji,
w przeciwnym razie przechodzi do kodu i przyczyny wysłanych przez serwer.
Wszystkie możliwe kody stanu i ich znaczenie zostały opisane w
lista kodów stanu CloseEvent
.
const {code, reason} = await chatWSS.closed;
Zamykanie połączenia WebSocketStream
Strumień WebSocketStream można zamknąć za pomocą
AbortController
Dlatego musisz przekazać AbortSignal
do konstruktora WebSocketStream
.
const controller = new AbortController();
const wss = new WebSocketStream(URL, {signal: controller.signal});
setTimeout(() => controller.abort(), 1000);
Możesz też użyć metody WebSocketStream.close()
,
ale jego głównym celem jest określenie
kod
i wyjaśnienie, które jest przesyłane na serwer.
wss.close({code: 4000, reason: 'Game over'});
Stopniowe ulepszanie i interoperacyjność
Obecnie Chrome jest jedyną przeglądarką, w której zaimplementowano interfejs WebSocketStream API.
Aby zapewnić interoperacyjność z klasycznym interfejsem WebSocket API,
nie można zastosować obciążenia wstecznego do odebranych wiadomości.
Zastosowanie wstecznego obciążenia do wysyłanych wiadomości jest możliwe, ale obejmuje odpytywanie
WebSocket.bufferedAmount
która jest niewydajna i nieergonomiczna.
Wykrywanie cech
Aby sprawdzić, czy interfejs WebSocketStream API jest obsługiwany, użyj polecenia:
if ('WebSocketStream' in window) {
// `WebSocketStream` is supported!
}
Prezentacja
W obsługiwanych przeglądarkach interfejs WebSocketStream API można zobaczyć w umieszczonym elemencie iframe, lub bezpośrednio w usłudze Glitch.
Prześlij opinię
Zespół Chrome chce poznać Twoją opinię na temat interfejsu WebSocketStream API.
Opowiedz nam o konstrukcji interfejsu API
Czy jest coś, co nie działa w interfejsie API zgodnie z oczekiwaniami? A może brakuje Ci metod lub właściwości, które pozwolą Ci zrealizować Twój pomysł? Masz pytanie lub komentarz na temat modelu zabezpieczeń? Zgłoś problem ze specyfikacją w odpowiednim repozytorium GitHub. lub opisz swój problem.
Zgłoś problem z implementacją
Czy wystąpił błąd z implementacją Chrome?
Czy implementacja różni się od specyfikacji?
Zgłoś błąd na new.crbug.com.
Postaraj się podać jak najwięcej szczegółów, proste instrukcje dotyczące odtwarzania,
i w polu Komponenty wpisz Blink>Network>WebSockets
.
Glitch doskonale sprawdza się w przypadku szybkiego i łatwego udostępniania zgłoszeń.
Pokaż wsparcie dla interfejsu API
Czy planujesz użycie interfejsu API WebSocketStream? Twoje publiczne wsparcie pomaga zespołowi Chrome ustalać priorytety funkcji i pokazuje innym dostawcom przeglądarek, jak ważne jest ich wsparcie.
Wyślij tweeta na adres @ChromiumDev, używając hashtagu
#WebSocketStream
.
i daj nam znać, gdzie i jak go używasz.
Przydatne linki
- Publiczne wyjaśnienie
- Prezentacja interfejsu WebSocketStream API | Źródło demonstracyjne interfejsu WebSocketStream API
- Śledzenie błędu
- Wpis na temat ChromeStatus.com
- Komponent Blink:
Blink>Network>WebSockets
Podziękowania
Interfejs WebSocketStream API został wdrożony przez Adam Rice i Yutaka Hirano Baner powitalny: Daan Mooij, w: Odchylenie.