Long Polling مقابل WebSocket في TypeScript: أيهما تختار للوقت الفعلي؟

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

عندما يتطلب الموقع "الحي" كوداً حياً

\n

تخيل: أنت تكتب تطبيق مراسلة باستخدام TypeScript. يرسل المستخدم رسالة — ويجب أن يراها الطرف الآخر فوراً، دون تحديث الصفحة. أو لوحة بورصة حيث يتغير سعر الأسهم كل ثانية. أو مجرد خلاصة إشعارات تُحدث نفسها بنفسها. كيف يمكن تحقيق ذلك؟ هناك مرشحان رئيسيان — long polling و WebSocket. لكن أيهما تختار حتى لا تفسد الأداء أو تكسر تجربة المستخدم؟

\n

في هذه المقالة، سنشرح من خلال أمثلة حقيقية بلغة TypeScript كيفية عمل كل تقنية، وأين تتألق، وأين تخذل. ستحصل ليس فقط على النظرية، بل أيضاً على أجزاء جاهزة من الكود لـ Node.js والمتصفح. هيا بنا!

\n\n

ما هو Long Polling في TypeScript وكيف يعمل

\n

Long polling هو تطور لطلب HTTP العادي. يرسل العميل طلباً إلى الخادم، لكن الخادم لا يرد فوراً إذا لم تكن هناك بيانات. إنه يبقي الاتصال مفتوحاً حتى يظهر حدث جديد. بمجرد أن تصبح البيانات جاهزة — يرسل الخادم الرد، ويعالجه العميل، ثم ينشئ على الفور طلباً جديداً. تتكرر الدورة.

\n

يبدو هذا كحل مؤقت؟ نوعاً ما. لكنه يعمل حتى عبر أكثر البروكسيات المؤسسية تشدداً التي تحظر WebSocket.

\n\n

تنفيذ Long Polling بلغة TypeScript (جانب الخادم)

\n

سنكتب خادماً بسيطاً باستخدام Express مع TypeScript. سيحاكي قائمة انتظار للرسائل.

\n
import express, { Request, Response } from 'express';\nimport cors from 'cors';\n\nconst app = express();\napp.use(cors());\napp.use(express.json());\n\n// تخزين الرسائل (محاكاة قائمة انتظار)\nconst messages: string[] = [];\n\n// نقطة نهاية لـ long polling\napp.get('/poll', (req: Request, res: Response) => {\n  // انتظار رسالة جديدة لمدة تصل إلى 30 ثانية\n  const checkForMessage = () => {\n    if (messages.length > 0) {\n      // إرسال أول رسالة وحذفها من قائمة الانتظار\n      const message = messages.shift();\n      res.json({ data: message, timestamp: Date.now() });\n    } else {\n      // إذا لم تكن هناك رسائل — استمر في الانتظار\n      setTimeout(checkForMessage, 1000); // تحقق كل ثانية\n    }\n  };\n\n  // مهلة في حال عدم وجود رسائل لفترة طويلة\n  const timeout = setTimeout(() => {\n    res.json({ data: null, timeout: true });\n  }, 30000);\n\n  // إذا قطع العميل الاتصال — نظف المؤقتات\n  req.on('close', () => {\n    clearTimeout(timeout);\n  });\n\n  checkForMessage();\n});\n\n// نقطة نهاية لإرسال رسالة\napp.post('/send', (req: Request, res: Response) => {\n  const { message } = req.body;\n  if (message) {\n    messages.push(message);\n    res.status(200).json({ status: 'ok' });\n  } else {\n    res.status(400).json({ error: 'message is required' });\n  }\n});\n\napp.listen(3000, () => console.log('Long poll server on port 3000'));
\n\n

الجزء العميل بلغة TypeScript (المتصفح)

\n
async function startLongPolling() {\n  try {\n    const response = await fetch('http://localhost:3000/poll');\n    const data = await response.json();\n\n    if (data.data) {\n      console.log('رسالة جديدة:', data.data);\n      // تحديث واجهة المستخدم\n      updateUI(data.data);\n    }\n\n    // بدء poll جديد فوراً\n    startLongPolling();\n  } catch (error) {\n    console.error('خطأ في long polling:', error);\n    // انتظر ثانيتين وحاول مرة أخرى\n    setTimeout(startLongPolling, 2000);\n  }\n}\n\nfunction updateUI(message: string) {\n  // الكود الخاص بك لتحديث DOM\n  const container = document.getElementById('messages');\n  if (container) {\n    const item = document.createElement('li');\n    item.textContent = message;\n    container.appendChild(item);\n  }\n}\n\n// البدء عند تحميل الصفحة\ndocument.addEventListener('DOMContentLoaded', startLongPolling);
\n

الخلاصة: long polling بسيط في التنفيذ ولا يتطلب بروتوكولات خاصة. لكن كل طلب هو عبارة عن رؤوس HTTP، وملفات تعريف ارتباط، وتكاليف إضافية. مع 1000 عميل متزامن

المدونات

توصيات الكتب