Long Polling مقابل WebSocket في JavaScript: معركة ملحمية من أجل الوقت الفعلي
\n\nفي زمن مضى، عندما كان الإنترنت بطيئًا والمتصفحات بسيطة، كانت الطريقة الوحيدة لمعرفة ما إذا كانت هناك بيانات جديدة على الخادم هي الضغط على F5. ثم ظهر AJAX، وتعلمنا كيفية استقصاء الخادم يدويًا. ولكن ماذا لو كان يجب أن تأتي البيانات من تلقاء نفسها، دون تدخل منا؟ مرحبًا بكم في عالم اتصالات الوقت الفعلي.
\n\nفي هذه المقالة، سنقوم بتحليل نهجين رئيسيين لا يزالان يقسمان مجتمع المطورين: النهج القديم الجيد Long Polling والنهج الحديث الجريء WebSocket. سنكتب كودًا بلغة JavaScript، ونلقي نظرة على آلياتهما الداخلية، ونفهم أي أداة تختار لمشروعك القادم. إذا كنت تريد فهم long polling vs websocket مرة واحدة وإلى الأبد، فأنت في المكان الصحيح.
\n\nالمشكلة: كيف تجعل الخادم يتحدث أولاً؟
\n\nHTTP هو بروتوكول أحادي الاتجاه. يرسل العميل (المتصفح) طلبًا، ويستجيب الخادم - وهذا كل شيء، انتهى الغداء. لكن في العالم الحقيقي (الدردشات، أسعار الأسهم، الإشعارات)، يجب أن تتدفق البيانات في الاتجاه المعاكس. لفترة طويلة، كان المطورون يتلاعبون. وإليك طريقتان رئيسيتان لحل هذه المشكلة.
\n\nLong Polling: خدعة ذكية مع الوقت
\n\nتخيل أنك تتصل بخدمة الدعم وتقول: "سأنتظر على الخط حتى يتوفر مشغل". أنت لا تغلق الخط. هذه هي بالضبط طريقة عمل Long Polling (المعروف أيضًا باسم "الاستقصاء الطويل").
\n\nكيف يعمل:
\n- \n
- يرسل العميل طلب HTTP عادي. \n
- لا يستجيب الخادم فورًا إذا لم تكن هناك بيانات. إنه "يعلق" وينتظر. \n
- بمجرد ظهور البيانات - يرسل الخادم الرد. \n
- يعالج العميل الرد ويفتح على الفور اتصالًا جديدًا. \n
الكود على جانب العميل (JavaScript):
\nfunction longPoll() {\n fetch('/updates')\n .then(response => response.json())\n .then(data => {\n console.log('بيانات جديدة:', data);\n // نبدأ استقصاءً جديدًا فورًا\n longPoll();\n })\n .catch(error => {\n console.error('خطأ، إعادة الاتصال بعد ثانيتين:', error);\n setTimeout(longPoll, 2000);\n });\n}\n\n// نبدأ التشغيل\nlongPoll();\n\nالمزايا:
\n- \n
- يعمل على أي خادم وأي متصفح (حتى IE6). \n
- لا يتطلب بروتوكولات خاصة - HTTP نقي. \n
- يمر عبر أي بروكسيات وجدران نارية مؤسسية. \n
العيوب:
\n- \n
- كل رسالة هي طلب HTTP جديد (رؤوس، ملفات تعريف ارتباط، تكاليف إضافية). \n
- يحتفظ الخادم بالعديد من الاتصالات المفتوحة (مشكلة C10k - 10 آلاف عميل). \n
- زمن الاستجابة (latency) أعلى من WebSocket. \n
WebSocket: قناة اتصال دائمة
\n\nWebSocket يشبه خطًا مفتوحًا بين سفينة فضاء ومركز التحكم. تقوم بإنشاء اتصال مرة واحدة، وبعد ذلك يمكن لكلا الطرفين إرسال البيانات في أي وقت، دون مراسم إضافية.
\n\nكيف يعمل:
\n- \n
- يبدأ العميل مصافحة (handshake) عبر HTTP. \n
- يقوم الخادم بتبديل البروتوكول إلى ws:// أو wss://. \n
- يتم إنشاء اتصال دائم ثنائي الاتجاه. \n
- يتم نقل البيانات عبر إطارات (frames) - خفيفة وسريعة. \n
الكود على جانب العميل (JavaScript):
\nconst socket = new WebSocket('wss://example.com/chat');\n\n// عندما يكون الاتصال مفتوحًا\nsocket.onopen = function() {\n console.log('تم إنشاء الاتصال');\n socket.send(JSON.stringify({ type: 'greeting', text: 'مرحبًا أيها الخادم!' }));\n};\n\n// عندما تصل رسالة\nsocket.onmessage = function(event) {\n const data = JSON.parse(event.data);\n console.log('رسالة من الخادم:', data);\n};\n\n// عند حدوث خطأ\nsocket.onerror = function(error) {\n console.error('خطأ في WebSocket:', error);\n};\n\n// عند الإغلاق\nsocket.onclose = function(event) {\n console.log('تم إغلاق الاتصال. الرمز:', even