مقدمه

پروتکل HTTP که پایه و اساس وب و Fetch API است، بر مدل «درخواست-پاسخ» (Request-Response) کار می‌کند: کلاینت یک درخواست ارسال می‌کند، سرور یک پاسخ می‌دهد، و ارتباط تمام می‌شود. این مدل برای دریافت اسناد وب عالی است، اما برای اپلیکیشن‌هایی که نیاز به ارتباطات زنده و دوطرفه دارند (مانند اپلیکیشن‌های چت، بازی‌های آنلاین، یا داشبوردهای مالی زنده) ناکارآمد است. در چنین سناریوهایی، کلاینت مجبور است به طور مداوم از سرور بپرسد (polling) که "آیا خبر جدیدی هست؟"، که این کار منابع شبکه و سرور را هدر می‌دهد.

Web Sockets یک تکنولوژی متفاوت است که برای حل این مشکل طراحی شده. این API به ما اجازه می‌دهد تا یک کانال ارتباطی پایدار، دوطرفه (full-duplex) و با تأخیر کم بین کلاینت و سرور ایجاد کنیم. پس از برقراری این ارتباط اولیه (که با یک handshake از طریق HTTP شروع می‌شود)، هر دو طرف می‌توانند در هر زمانی که بخواهند، داده‌ها را برای طرف دیگر ارسال کنند، بدون نیاز به ارسال یک درخواست HTTP جدید برای هر پیام.

برقراری یک اتصال WebSocket

برای شروع یک ارتباط WebSocket، کافیست یک نمونه جدید از شیء WebSocket را با آدرس URL سرور WebSocket خود بسازیم. این URLها با پروتکل‌های خاص ws:// (برای ارتباطات غیرامن) و wss:// (برای ارتباطات امن و رمزنگاری شده) شروع می‌شوند. در محیط پروداکشن، استفاده از wss ضروری است.

Copy Icon JAVASCRIPT
// The server at this address must be configured to handle WebSocket connections.
const socket = new WebSocket('wss://sockets.example.com/chat');

به محض ساخت این شیء، مرورگر تلاش می‌کند تا در پس‌زمینه ارتباط با سرور را برقرار کند. ما نمی‌توانیم مستقیماً وضعیت این فرآیند را کنترل کنیم، بلکه باید با استفاده از شنوندگان رویداد، به مراحل مختلف چرخه حیات این اتصال واکنش نشان دهیم.

چرخه حیات یک اتصال WebSocket

تعامل با یک شیء WebSocket کاملاً رویداد-محور است. ما با ثبت شنوندگان برای چهار رویداد اصلی، چرخه حیات اتصال را مدیریت می‌کنیم.

  • open: زمانی که ارتباط با موفقیت برقرار شد، این رویداد اجرا می‌شود. این تنها زمانی است که می‌توانیم با اطمینان شروع به ارسال پیام کنیم.
  • message: هر بار که یک پیام از سرور دریافت می‌شود، این رویداد اجرا می‌شود. خود پیام در پراپرتی event.data قرار دارد.
  • error: در صورت بروز خطایی در ارتباط، این رویداد اجرا می‌شود.
  • close: زمانی که ارتباط (چه به صورت تمیز توسط کلاینت یا سرور، و چه به دلیل یک مشکل شبکه‌ای) بسته می‌شود، این رویداد اجرا می‌شود.
Copy Icon JAVASCRIPT
const socket = new WebSocket('wss://sockets.example.com/chat');

// 1. Connection opened successfully
socket.addEventListener('open', (event) => {
    console.log('Connected to the WebSocket server!');
    // Now it's safe to send a message
    socket.send('Hello Server, I am connected.');
});

// 2. Listen for messages from the server
socket.addEventListener('message', (event) => {
    console.log('Message from server:', event.data);
});

// 3. Handle connection errors
socket.addEventListener('error', (event) => {
    console.error('WebSocket Error:', event);
});

// 4. Connection closed
socket.addEventListener('close', (event) => {
    if (event.wasClean) {
        console.log(`Connection closed cleanly, code=${event.code}, reason=${event.reason}`);
    } else {
        // e.g., server process killed or network error
        console.error('Connection died unexpectedly.');
    }
});

این کد ساختار کامل مدیریت یک اتصال WebSocket را نشان می‌دهد. پس از برقراری اتصال در رویداد open، یک پیام اولیه ارسال می‌شود. سپس در رویداد message منتظر پاسخ‌ها یا پیام‌های بعدی از سرور می‌مانیم و در نهایت رویدادهای error و close را برای مدیریت مشکلات یا پایان اتصال، مدیریت می‌کنیم.

ارسال داده و بستن اتصال

برای ارسال داده به سرور، از متد socket.send(data) استفاده می‌کنیم. داده ارسالی معمولاً یک رشته است که در بسیاری از موارد، یک رشته JSON شده از یک شیء جاوااسکریپت می‌باشد.

برای بستن اتصال از سمت کلاینت به صورت تمیز، متد socket.close() را فراخوانی می‌کنیم. همیشه بهتر است قبل از بستن صفحه، اتصالات فعال WebSocket را ببندیم.

Copy Icon JAVASCRIPT
const sendBtn = document.getElementById('send-btn');
const msgInput = document.getElementById('message-input');

sendBtn.addEventListener('click', () => {
    const message = msgInput.value;
    // Check if the connection is open before sending
    if (message && socket.readyState === WebSocket.OPEN) {
        const messageObject = { type: 'chat', text: message };
        socket.send(JSON.stringify(messageObject));
        msgInput.value = '';
    }
});

این مثال یک رابط کاربری ساده چت را نشان می‌دهد. قبل از ارسال پیام، با بررسی پراپرتی socket.readyState مطمئن می‌شویم که اتصال باز است.

در این درس با قدرت Web Sockets برای ساخت اپلیکیشن‌های زنده و تعاملی آشنا شدیم. این تکنولوژی که یک کانال ارتباطی دوطرفه و پایدار فراهم می‌کند، برای اپلیکیشن‌هایی مانند چت، بازی‌های آنلاین و داشبوردهای اطلاعاتی زنده، یک استاندارد صنعتی محسوب می‌شود. در درس پایانی این فصل، با Eventsource API یا Server-Sent Events (SSE) آشنا خواهیم شد که یک راه حل ساده‌تر برای ارتباط یک‌طرفه و زنده از سرور به کلاینت ارائه می‌دهد.