ป้องกันไม่ให้แอปจมอยู่กับข้อความ WebSocket หรือทำให้เซิร์ฟเวอร์ WebSocket ทำงานหนักเกินไปด้วยข้อความที่ใช้แรงกดดัน
ข้อมูลเบื้องต้น
WebSocket API
WebSocket API จัดเตรียมอินเทอร์เฟซ JavaScript ให้กับโปรโตคอล WebSocket ซึ่งทำให้สามารถเปิดเซสชันการสื่อสารแบบ 2 ทาง ระหว่างเบราว์เซอร์ของผู้ใช้และเซิร์ฟเวอร์ คุณสามารถใช้ API นี้ในการส่งข้อความไปยังเซิร์ฟเวอร์และรับการตอบกลับที่ขับเคลื่อนด้วยเหตุการณ์ได้ โดยไม่ต้องสำรวจเซิร์ฟเวอร์เพื่อตอบกลับ
API ของสตรีม
Streams API อนุญาตให้ JavaScript เข้าถึงสตรีมข้อมูลที่ได้รับผ่านเครือข่ายแบบเป็นโปรแกรมได้ และประมวลผลได้ตามต้องการ แนวคิดสำคัญในบริบทของสตรีมคือ backpressure นี่คือกระบวนการที่สตรีมเดียวหรือโซ่ไปป์ ควบคุมความเร็วในการอ่านหรือเขียน เมื่อสตรีมนั้นเองหรือสตรีมในภายหลังในห่วงโซ่ไปป์ยังคงไม่ว่าง และยังไม่พร้อมที่จะรองรับกลุ่มอื่นๆ อีก โดยจะส่งสัญญาณย้อนกลับผ่านห่วงโซ่เพื่อชะลอการนำส่งตามความเหมาะสม
ปัญหาเกี่ยวกับ WebSocket API ปัจจุบัน
ใช้แรงดันย้อนกลับกับข้อความที่ได้รับไม่ได้
เมื่อใช้ WebSocket API ปัจจุบัน การแสดงความรู้สึกต่อข้อความจะเกิดขึ้นใน
WebSocket.onmessage
EventHandler
ที่เรียกเมื่อได้รับข้อความจากเซิร์ฟเวอร์
สมมติว่าคุณมีแอปพลิเคชันที่จำเป็นต้องดำเนินการประมวลผลข้อมูลขนาดใหญ่
เมื่อใดก็ตามที่ได้รับข้อความใหม่
คุณก็น่าจะตั้งค่าขั้นตอนให้เหมือนกับโค้ดด้านล่างนี้
และเนื่องจากคุณ await
ผลของการเรียก process()
ก็น่าจะดีใช่ไหม
// 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);
};
ผิด ปัญหาของ WebSocket API ปัจจุบันคือไม่มีวิธีที่จะใช้ Backpressure
เมื่อข้อความมาถึงเร็วกว่าที่เมธอด process()
จะจัดการได้
กระบวนการแสดงผลจะทำให้หน่วยความจำเต็ม
โดยการบัฟเฟอร์ข้อความเหล่านั้น
ไม่ตอบสนองเนื่องจากการใช้งาน CPU 100% หรือทั้งสองอย่าง
การใช้แรงกดดันย้อนกลับกับข้อความที่ส่งไม่เป็นไปตามหลักการยศาสตร์
คุณสามารถทำได้โดยใช้แรงกดดันย้อนกลับกับข้อความที่ส่ง แต่จะต้องมีการสำรวจ
WebSocket.bufferedAmount
ที่ไร้ประสิทธิภาพและไม่ผิดหลักสรีรศาสตร์
พร็อพเพอร์ตี้แบบอ่านอย่างเดียวนี้จะแสดงจำนวนไบต์ของข้อมูลที่อยู่ในคิว
โดยใช้การโทรไปยัง
WebSocket.send()
แต่ยังไม่ได้ส่งไปยังเครือข่าย
ค่านี้จะรีเซ็ตเป็น 0 เมื่อส่งข้อมูลที่อยู่ในคิวทั้งหมดแล้ว
แต่ถ้าคุณโทรหา WebSocket.send()
ซ้ำๆ
โมเดลก็จะปีนต่อไป
WebSocketStream API คืออะไร
WebSocketStream API รับมือกับปัญหาความดันย้อนกลับที่ไม่มีอยู่หรือไม่ได้ถูกสรีรศาสตร์ ด้วยการผสานรวมสตรีมกับ WebSocket API ซึ่งหมายความว่าคุณจะใช้แรงดันย้อนกลับ "ฟรี" ได้โดยไม่มีค่าใช้จ่ายเพิ่มเติม
กรณีการใช้งานที่แนะนำสำหรับ WebSocketStream API
ตัวอย่างเว็บไซต์ที่ใช้ API นี้ได้ ได้แก่
- แอปพลิเคชัน WebSocket แบบแบนด์วิดท์สูงที่จำเป็นต้องรักษาการโต้ตอบ โดยเฉพาะวิดีโอ และการแชร์หน้าจอ
- ในทำนองเดียวกัน การจับภาพวิดีโอและแอปพลิเคชันอื่นๆ ที่สร้างข้อมูลจำนวนมากในเบราว์เซอร์ ที่จะอัปโหลดไปยังเซิร์ฟเวอร์ การใช้แรงดันย้อนกลับจะทำให้ไคลเอ็นต์หยุดสร้างข้อมูลแทนการสะสมข้อมูลในหน่วยความจำ
สถานะปัจจุบัน
ขั้นตอน | สถานะ |
---|---|
1. สร้างคำอธิบาย | เสร็จสมบูรณ์ |
2. สร้างข้อกำหนดคร่าวๆ เบื้องต้น | กำลังดำเนินการ |
3. รวบรวมความคิดเห็นและ ทำซ้ำในการออกแบบ | กำลังดำเนินการ |
4. ช่วงทดลองใช้จากต้นทาง | เสร็จสมบูรณ์ |
5. เปิดตัว | ยังไม่เริ่ม |
วิธีใช้ WebSocketStream API
ตัวอย่างแนะนำ
WebSocketStream API ทำตามสัญญา ซึ่งช่วยให้จัดการสิ่งต่างๆ ได้อย่างเป็นธรรมชาติ
ในโลก JavaScript สมัยใหม่
คุณเริ่มต้นด้วยการสร้าง WebSocketStream
ใหม่และส่ง URL ของเซิร์ฟเวอร์ WebSocket ไปให้
ถัดไป คุณต้องรอให้การเชื่อมต่อเป็น opened
ซึ่งส่งผลให้เกิด
ReadableStream
และ/หรือ
WritableStream
โดยการเรียกใช้
ReadableStream.getReader()
คุณจะได้รับ
ReadableStreamDefaultReader
,
จากนั้นคุณสามารถ read()
ข้อมูลจากจนกว่าสตรีมจะเสร็จสมบูรณ์ กล่าวคือ จนกว่าสตรีมจะส่งกลับออบเจ็กต์ของฟอร์ม
{value: undefined, done: true}
ด้วยเหตุนี้ การเรียกใช้โค้ด
WritableStream.getWriter()
คุณจะได้รับ
WritableStreamDefaultWriter
,
จากนั้นคุณสามารถ 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);
}
แรงกดดันด้านหลัง
แล้วฟีเจอร์ Backpressure ตามที่สัญญาไว้มีอะไรบ้าง
ตามที่เราได้กล่าวไว้ข้างต้น คุณจะใช้งานได้แบบ "ฟรี" โดยไม่ต้องดำเนินการใดๆ เพิ่มเติม
หาก process()
ใช้เวลานานขึ้น ระบบจะใช้งานข้อความถัดไปเมื่อไปป์ไลน์พร้อมใช้งานแล้วเท่านั้น
เช่นเดียวกับขั้นตอน WritableStreamDefaultWriter.write()
จะดำเนินการต่อเมื่อทำได้อย่างปลอดภัยเท่านั้น
ตัวอย่างขั้นสูง
อาร์กิวเมนต์ที่สองของ WebSocketStream เป็นกระเป๋าสำหรับใช้ขยายเวลาในอนาคต
ปัจจุบันตัวเลือกเดียวคือ protocols
ซึ่งมีลักษณะการทำงานเหมือนกับ
อาร์กิวเมนต์ที่สองไปยังตัวสร้าง WebSocket:
const chatWSS = new WebSocketStream(CHAT_URL, {protocols: ['chat', 'chatv2']});
const {protocol} = await chatWSS.opened;
protocol
ที่เลือกและ extensions
ที่เป็นไปได้เป็นส่วนหนึ่งของพจนานุกรม
พร้อมใช้งานผ่านสัญญา WebSocketStream.opened
สัญญานี้ให้ข้อมูลทั้งหมดเกี่ยวกับการเชื่อมต่อแบบถ่ายทอดสด
เนื่องจากไม่มีความเกี่ยวข้องหากการเชื่อมต่อล้มเหลว
const {readable, writable, protocol, extensions} = await chatWSS.opened;
ข้อมูลเกี่ยวกับการเชื่อมต่อ WebSocketStream แบบปิด
ข้อมูลที่พร้อมใช้งานจาก
WebSocket.onclose
และ
WebSocket.onerror
กิจกรรม
ใน WebSocket API พร้อมให้บริการแล้วผ่าน WebSocketStream.closed
คำสัญญาจะปฏิเสธในกรณีที่การปิดการขายอย่างไม่สะอาด
มิเช่นนั้น ก็จะเปลี่ยนเป็นโค้ดและเหตุผลที่เซิร์ฟเวอร์ส่งมา
รหัสสถานะที่เป็นไปได้ทั้งหมดและความหมายมีอธิบายอยู่ใน
รายการรหัสสถานะ CloseEvent
const {code, reason} = await chatWSS.closed;
การปิดการเชื่อมต่อ WebSocketStream
สามารถปิด WebSocketStream ได้ด้วย
AbortController
ดังนั้น ให้ส่งค่า AbortSignal
ไปยังตัวสร้าง WebSocketStream
const controller = new AbortController();
const wss = new WebSocketStream(URL, {signal: controller.signal});
setTimeout(() => controller.abort(), 1000);
หรือคุณจะใช้เมธอด WebSocketStream.close()
แทนก็ได้
แต่วัตถุประสงค์หลักคืออนุญาตให้ระบุ
รหัส
และเหตุผลที่ส่งไปยังเซิร์ฟเวอร์
wss.close({code: 4000, reason: 'Game over'});
การเพิ่มประสิทธิภาพแบบต่อเนื่องและความสามารถในการทำงานร่วมกัน
ปัจจุบัน Chrome เป็นเบราว์เซอร์เดียวที่ใช้ WebSocketStream API
สำหรับความสามารถในการทำงานร่วมกับ WebSocket API แบบคลาสสิก
ไม่สามารถใช้แรงดันย้อนกลับกับข้อความที่ได้รับ
คุณสามารถทำได้โดยใช้แรงกดดันย้อนกลับกับข้อความที่ส่ง แต่จะต้องมีการสำรวจ
WebSocket.bufferedAmount
ที่ไร้ประสิทธิภาพและไม่ผิดหลักสรีรศาสตร์
การตรวจหาฟีเจอร์
หากต้องการตรวจสอบว่าระบบรองรับ WebSocketStream API หรือไม่ ให้ใช้รายการต่อไปนี้
if ('WebSocketStream' in window) {
// `WebSocketStream` is supported!
}
สาธิต
ในเบราว์เซอร์ที่รองรับ คุณสามารถดูการทำงานของ WebSocketStream API ใน iframe ที่ฝังไว้ หรือใน Glitch โดยตรง
ความคิดเห็น
ทีม Chrome ต้องการทราบประสบการณ์ของคุณในการใช้งาน WebSocketStream API
บอกเราเกี่ยวกับการออกแบบ API
มีบางอย่างเกี่ยวกับ API ที่ไม่ทำงานตามที่คุณคาดหวังหรือไม่ หรือขาดวิธีการหรือคุณสมบัติที่จำเป็นซึ่งจำเป็นต่อการนำไอเดียของคุณไปปฏิบัติ หากมีคำถามหรือความคิดเห็นเกี่ยวกับรูปแบบการรักษาความปลอดภัย แจ้งปัญหาเกี่ยวกับที่เก็บ GitHub ที่เกี่ยวข้อง หรือเพิ่มความคิดของคุณลงในปัญหาที่มีอยู่
รายงานปัญหาเกี่ยวกับการติดตั้งใช้งาน
คุณพบข้อบกพร่องในการติดตั้งใช้งาน Chrome ไหม
หรือการติดตั้งใช้งานแตกต่างจากข้อกําหนดหรือไม่
รายงานข้อบกพร่องที่ new.crbug.com
โปรดใส่รายละเอียดให้มากที่สุดเท่าที่จะเป็นไปได้ วิธีการง่ายๆ ในการทำซ้ำ
แล้วป้อน Blink>Network>WebSockets
ในช่องคอมโพเนนต์
Glitch เหมาะสำหรับการแชร์เคสการทำซ้ำที่ง่ายและรวดเร็ว
แสดงการรองรับ API
คุณกำลังวางแผนที่จะใช้ WebSocketStream API ใช่ไหม การสนับสนุนแบบสาธารณะของคุณช่วยให้ทีม Chrome จัดลำดับความสำคัญของฟีเจอร์ต่างๆ ได้ และแสดงให้ผู้ให้บริการเบราว์เซอร์รายอื่นเห็นถึงความสำคัญในการสนับสนุนของตน
ส่งทวีตไปยัง @ChromiumDev โดยใช้แฮชแท็ก
#WebSocketStream
และแจ้งให้เราทราบถึงตำแหน่งและวิธีที่คุณใช้งาน
ลิงก์ที่มีประโยชน์
- คำอธิบายแบบสาธารณะ
- การสาธิต WebSocketStream API | แหล่งข้อมูลสาธิต WebSocketStream API
- ข้อบกพร่องในการติดตาม
- รายการ ChromeStatus.com
- คอมโพเนนต์กะพริบ:
Blink>Network>WebSockets
กิตติกรรมประกาศ
WebSocketStream API ดำเนินการโดย Adam Rice และ ยูทากะ ฮิราโนะ รูปภาพหลักโดย Daan Mooij ใน หน้าจอแนะนํา