Sending and Receiving
เมื่อการเชื่อมต่อเป็น OPEN แล้ว งานประจำวันมีแค่สองอย่าง: ผลักข้อความออกไปด้วย send() และตอบสนองต่อข้อความที่เข้ามาผ่าน message event บทเรียนนี้ตอกย้ำทั้งสองทิศทาง บวกกับสองกฎที่ทำให้คนสะดุดมากที่สุด — ส่งได้ เมื่อไหร่ และสิ่งต่าง ๆ มาถึง ตามลำดับใด
การส่งด้วย ws.send()
หัวข้อที่มีชื่อว่า “การส่งด้วย ws.send()”ในการส่ง คุณเรียก send() พร้อม payload ของคุณ:
ws.send('hello, server');ws.send(JSON.stringify({ type: 'chat', text: 'hi' }));send() รับ string หรือ binary data (เรื่อง binary อยู่ในบทถัดไป) ไม่ คืนค่าอะไรและไม่มีการตอบรับ — แค่ยื่น message ให้การเชื่อมต่อเท่านั้น รูปแบบที่พบบ่อยคือส่งข้อมูลที่มีโครงสร้างโดยแปลง object เป็น JSON แล้ว parse ที่อีกฝั่ง
การรับผ่าน message event
หัวข้อที่มีชื่อว่า “การรับผ่าน message event”ข้อความที่เข้ามาจะมาถึงในรูปของ message event และ payload จะอยู่บน event.data เสมอ:
ws.onmessage = (event) => { const data = event.data; // a string (or binary, next lesson) const msg = JSON.parse(data); // if the peer sent JSON console.log(msg.type, msg.text);};event.data คือ ที่เดียว ที่ payload อยู่ ถ้าส่ง JSON มาก็ parse ตรงนี้ ถ้าส่ง text ธรรมดามาก็ใช้ได้เลย handler ทำงานหนึ่งครั้งต่อหนึ่ง message และยิงบ่อยเท่าที่ server มีเรื่องจะพูด
คุณส่งได้เฉพาะตอน OPEN เท่านั้น
หัวข้อที่มีชื่อว่า “คุณส่งได้เฉพาะตอน OPEN เท่านั้น”นี่คือกฎเดียวที่ควรสักไว้ในความทรงจำ: send() ใช้ได้เฉพาะขณะที่ readyState เป็น OPEN เท่านั้น
- เรียก
send()ขณะยังเป็นCONNECTINGจะ throwInvalidStateError— การเชื่อมต่อยังไม่พร้อม - เรียก
send()หลังCLOSINGหรือCLOSEDข้อมูลจะถูกทิ้งเงียบ ๆ ไม่มีวันถึง peer
ดังนั้นรูปแบบที่ปลอดภัยคือส่งจากภายใน onopen หรือใส่ guard ให้ทุกการเรียก:
function safeSend(ws: WebSocket, data: string) { if (ws.readyState === WebSocket.OPEN) { ws.send(data); } else { console.warn('not open — dropping or queuing message'); }}ลำดับถูกรับประกัน
หัวข้อที่มีชื่อว่า “ลำดับถูกรับประกัน”WebSocket ทำงานบนการเชื่อมต่อ TCP เดียว และนั่นมอบการรับประกันที่หนักแน่นและเรียบง่ายให้คุณ: ข้อความถูกส่งถึงตามลำดับที่คุณส่งออกไป ถ้าคุณเรียก send('a') แล้ว send('b') แล้ว send('c') peer จะได้รับ a, b, c — ไม่มีวันสลับลำดับ ไม่มีวันซ้ำ เช่นเดียวกันกับข้อความที่ server ส่งมาหาคุณ
sequenceDiagram
participant App as Your code
participant WS as WebSocket
participant Srv as Server
Note over WS: readyState = OPEN
App->>WS: send("a")
App->>WS: send("b")
WS->>Srv: a
WS->>Srv: b
Srv-->>WS: reply to a
WS-->>App: message event (data = reply to a)
Srv-->>WS: reply to b
WS-->>App: message event (data = reply to b) สิ่งที่ลำดับ ไม่ รับประกันคือการจับคู่ request/response WebSocket ไม่มีแนวคิดในตัวว่า “การตอบกลับนี้เป็นของการส่งนั้น” — ถ้าคุณต้องการแบบนั้น คุณต้องเพิ่ม correlation id ของคุณเองไว้ในข้อความ ลำดับ ใช่; การจับคู่ นั่นเป็นหน้าที่ของคุณ
ส่งและรับ แบบสด
หัวข้อที่มีชื่อว่า “ส่งและรับ แบบสด”เดโมใช้ echo socket ในหน้าเว็บที่มี WebSocket API จริง จึงรันได้ทุกที่โดยไม่ต้องมี server เดโมส่งสาม message ติดกันจากใน onopen แล้วพิมพ์ echo แต่ละตัวตอนกลับมา — เรียงตามลำดับ ในแอปจริงมีแค่บรรทัดแรกที่เปลี่ยนเป็น new WebSocket('wss://your-server')
สังเกตว่าความพยายามแรก — too early — ถูกบล็อกเพราะ socket ยังเป็น CONNECTING อยู่ จากนั้นพอเปิดแล้ว สาม message ที่มีหมายเลขก็กลับมาเป็น 1, 2, 3 ตรงตามลำดับที่ส่งออกไปเป๊ะ นั่นคือ send(), message event, กฎ OPEN-only และลำดับ ทั้งหมดในการรันครั้งเดียว
| Data Type | ส่งด้วย | รับเป็น | เหมาะกับ |
|---|---|---|---|
| String | ws.send("text") | event.data เป็น string | JSON message, text protocol |
| ArrayBuffer | ws.send(buffer) | event.data เป็น ArrayBuffer | binary data, fixed structure |
| Blob | ws.send(blob) | event.data เป็น Blob | file, image, audio |
ข้อผิดพลาดที่พบบ่อย
หัวข้อที่มีชื่อว่า “ข้อผิดพลาดที่พบบ่อย”Parse JSON ทุก Message โดยไม่มี Error Handling อาการ:
JSON.parse(event.data)โดยไม่ try/catch- server ส่ง malformed JSON → app crash
- wrap ใน try/catch:
try { const msg = JSON.parse(event.data); } catch (e) { console.error('Invalid message', e) }
ส่ง Message ขนาดใหญ่ใน Loop โดยไม่ Check bufferedAmount อาการ:
- loop ส่ง frame ติดกัน 1000 ครั้ง — buffer ล้น
ws.bufferedAmountสูงมาก — memory spike- check
ws.bufferedAmount < thresholdก่อนส่ง message ถัดไป
💡 ตัวอย่างจากของจริง
Slack:
- รับ message เป็น JSON:
{ "type": "message", "text": "Hello", "channel": "C1234" }- dispatch ตาม
typefield — event-driven message handlingGoogle Docs:
- ส่ง operation เป็น binary (OT operations) — compact และเร็ว
- รับ update จาก server และ apply ต่อ document state local