ليه React Server Components ظهرت؟
قبل السؤال دا لازم الأول نفهم الـClient-Side Rendering (CSR) والـServer-Side Rendering (SSR) وال ـStatic Site Generation (SSG)
هشرحلك كل حاجة بالتفصيل وبأمثلة عملية عشان تفهم الفرق بينهم كويس.
أولاً: CSR (Client-Side Rendering)
تخيل إنك رايح مطعم، وبدل ما تلاقي الأكل جاهز، المطعم يديك المكونات كلها والوصفة وتطبخ الأكل بنفسك في البيت. ده تقريباً شبه الـ CSR.
في الـ CSR، السيرفر بيبعت ملف HTML فاضي تقريباً مع ملفات JavaScript كبيرة. المتصفح (اللي هو الـ client) هو اللي بيشتغل ويبني الصفحة كلها من الصفر. زي لما تفتح موقع زي Facebook في أول مرة، بتلاقي صفحة بيضا وبعدين الموقع بيتحمل.
مميزات CSR:
- بيدي تجربة مستخدم تفاعلية جداً
- سهل التطوير والتعديل
- بيقلل الحمل على السيرفر
عيوبه:
- بطيء في التحميل الأولي
- مش كويس للـ SEO
- بياخد موارد كتير من جهاز المستخدم
ثانياً: SSR (Server-Side Rendering)
دلوقتي تخيل إنك رايح نفس المطعم، بس المرة دي الأكل جاهز وساخن ومتقدم في طبق. ده الـ SSR.
في الـ SSR، السيرفر هو اللي بيجهز الصفحة كاملة بكل محتوياتها وبيبعتها للمتصفح. يعني لما تطلب الصفحة، السيرفر بيجهز HTML كامل بكل المحتوى وبيبعته.
مميزات SSR:
- تحميل أولي أسرع
- أحسن للـ SEO
- مناسب للمحتوى المتغير باستمرار
عيوبه:
- بيحتاج hydration (هشرحها حالاً)
- ضغط أكبر على السيرفر
- التفاعل مع الصفحة ممكن يكون أبطأ شوية
ثالثاً: SSG (Static Site Generation)
تخيل دلوقتي إن المطعم بيجهز كل الأكل مرة واحدة، وبيحطه في علب وبيخزنه. أي حد يطلب أكل بياخد علبة جاهزة على طول. ده الـ SSG.
في الـ SSG، الصفحات بتتبني مرة واحدة وقت الـ build، وبتتخزن كملفات HTML جاهزة. أي طلب بيرجع الملف الجاهز على طول.
مميزات SSG:
- سريع جداً في عرض المحتوى
- أمان عالي
- تكلفة استضافة قليلة
عيوبه:
- مش مناسب للمحتوى اللي بيتغير كتير
- أي تغيير بيحتاج rebuild للموقع كله
- محدود في التفاعلية
كدا نكون فاهمين إن
- CSR مناسب للتطبيقات التفاعلية جداً زي ألعاب الويب
- SSR مناسب للمواقع اللي محتواها بيتغير كتير زي مواقع الأخبار
- SSG مناسب للمواقع الثابتة زي المدونات ومواقع الشركات
أخيراً: الـ Hydration تخيل إنك جبت أكل جاهز من المطعم (SSR)، بس عشان تاكله لازم تسخنه الأول. ده الـ hydration.
الـ hydration هي عملية بتحصل بعد ما المتصفح يستلم الـ HTML من الـ SSR. المتصفح بيحمل ملفات JavaScript وبيربطها بالـ HTML الموجود عشان يخلي الصفحة تفاعلية. يعني الصفحة موجودة وباينة، بس مش هتقدر تتفاعل معاها (تضغط على أزرار، تملي فورم، إلخ) إلا بعد ما الـ hydration تخلص.
المشكلة الرئيسية في الـ hydration إنها بتحتاج موارد كتير من المتصفح وبتاخد وقت، وده بيأثر على تجربة المستخدم.
عملية الـ hydration بتتم على عدة مراحل:
المرحلة الأولى: التحميل الأولي
السيرفر بيبعت HTML كامل فيه كل العناصر والمحتوى (DOM nodes) المتصفح بيعرض الـ HTML ده على طول، فالمستخدم بيشوف المحتوى بسرعة لكن في المرحلة دي، الصفحة static تماماً - يعني مفيش event listeners ولا state management
المرحلة التانية: تحميل الـ JavaScript
// مثال لكود React بسيط
function Button({ onClick, children }) {
// في المرحلة الأولى، الزر ده موجود في الـ HTML بس مش interactive
return <button onClick={onClick}>{children}</button>;
}
// hydration بيبدأ هنا
const root = ReactDOM.hydrateRoot(
document.getElementById('root'),
<Button onClick={() => alert('تم الضغط!')}>اضغط هنا</Button>
);
المرحلة التالتة: عملية الـ Reconciliation
React (أو أي framework) بيبدأ يقارن الـ DOM الموجود مع الـ Virtual DOM بتاعه بيتأكد إن الـ structure متطابق لو في اختلاف، ده ممكن يسبب hydration mismatch errors كل طريقة من دول ليها استخدامها المناسب:
// مثال لـ hydration mismatch
// Server-side rendered HTML
<div id="root">
<button>اضغط هنا</button>
</div>
// Client-side JavaScript
ReactDOM.hydrateRoot(
document.getElementById('root'),
// Error: Hydration failed - محتوى مختلف
<button>زر مختلف</button>
);
المرحلة الرابعة: إضافة الـ Interactivity
// مثال لإضافة state management
function Counter() {
// هنا بيتم تهيئة الـ state handlers
const [count, setCount] = React.useState(0);
// إضافة event listeners
return (
<div>
<span>العدد: {count}</span>
<button onClick={() => setCount(c => c + 1)}>زيادة</button>
</div>
);
}
المرحلة الخامسة: إعداد الـ Event Delegation
// React بيستخدم نظام event delegation
document.getElementById('root').addEventListener('click', (event) => {
// يتم التعامل مع كل الـ click events من خلال handler واحد
// بدل ما نضيف handler لكل عنصر
const clickedElement = event.target;
// تنفيذ الـ onClick handler المناسب
});
الـ Performance Implications:
- الـ JavaScript Bundle Size بيأثر مباشرة على وقت الـ hydration
- كل ما الـ component tree أكبر، كل ما الـ hydration بياخد وقت أطول
- الـ Memory Usage بيزيد أثناء الـ hydration لأن في نسختين من الـ tree في الذاكرة
ليه React Server Components ظهرت؟
الهدف الأساسي من RSC هو تحسين تجربة المستخدم والأداء العام لتطبيقات الويب الكبيرة عن طريق تقليل حجم الـjs Bundle اللي بيحمله الـClient (المتصفح) مع الحفاظ على نفس الـfeatures اللي بتقدمها React.
مثال بسيط
بالنسبة للـ CSR، تخيل إنك بتفتح محل كبير. في الطريقة دي، إنت بتجيب كل البضاعة مرة واحدة في أول ما تفتح المحل، حتى لو الزبون عايز حاجة واحدة بس. يعني لو عندك موقع فيه 100 صفحة، المتصفح هيحمل كود الـ 100 صفحة دول، حتى لو المستخدم عايز يشوف صفحة واحدة بس. ده طبعاً بيخلي الموقع تقيل وبطيء، خصوصاً لو حد بيفتح الموقع من موبايل قديم أو نت ضعيف. أما الـ SSR، فده زي إنك بتجهز الطلب للزبون قبل ما يجي. حلو؟ أه، بس المشكلة إن لما الصفحة توصل للمستخدم، المتصفح برضه محتاج يعمل شغل إضافي (الـ hydration). تخيل إنك بعتت الأكل للزبون، بس لازم يسخنه تاني قبل ما ياكله. الـ hydration ده بياخد وقت ويستهلك موارد الجهاز، وأحياناً بيكون أبطأ من الـ CSR نفسه. والـ SSG، ده كويس جداً للمواقع الثابتة زي المدونات أو مواقع الشركات البسيطة. لكن تخيل لو عندك موقع زي تويتر مثلاً، هتحتاج تبني الموقع كله من جديد كل ما حد يعمل تويتة جديدة! ده مش عملي خالص. ليه دي مشاكل كبيرة؟ لأن في عصرنا ده، سرعة تحميل المواقع بقت مهمة جداً:
الناس مش بتستحمل تستنى أكتر من ثواني معدودة جوجل بيعتبر سرعة الموقع عامل مهم في الـ SEO في ناس كتير بتفتح المواقع من موبايلات وشبكات إنترنت ضعيفة
عشان كده ظهر الـ RSC كحل للمشاكل دي كلها. هو بيحاول ياخد أحسن ما في كل طريقة ويتجنب عيوبها. زي ما نقول إنه بيجمع بين مرونة الـ CSR، وسرعة الـ SSR، وكفاءة الـ SSG، بس من غير المشاكل اللي في كل واحد فيهم.
المشاكل اللي كانت موجودة قبل RSC:
الـClient-Side Rendering (CSR): كل الكود بيتنفذ بالكامل في المتصفح (الـClient)، وده معناه:
إن كل ملفات الـ JavaScript بتتحمل عند فتح الصفحة، حتى لو كان فيه أجزاء مش ضرورية حاليًا.
الأداء بيتأثر سلبًا، خصوصًا على الأجهزة الضعيفة أو الشبكات البطيئة.
الـServer-Side Rendering (SSR) بيحل مشكلة بطء تحميل الصفحة الأولي عن طريق تقديم صفحة HTML جاهزة من السيرفر
لكن لما الصفحة توصل للمستخدم، بيحتاج المتصفح إعادة تفعيل الـ components عن طريق عملية اسمها hydration.
المشكلة إن الـ hydration بتتطلب كمية ضخمة من الـ JavaScript، وده بيأثر على الأداء، زي ما لو بنشتغل بـ CSR.
الـStatic Site Generation (SSG):
- مناسب جدًا للصفحات الثابتة.
- لكن مع التطبيقات الديناميكية، أي تغييرات على البيانات بتتطلب إعادة بناء (rebuild) للموقع بالكامل، وده ممكن يكون غير عملي في حالات التحديث المستمر.
قبل ما نغوص في التفاصيل، لازم نفهم ليه الموضوع ده مهم. React Server Components مش مجرد فيتشر جديد، ده تغيير جذري في طريقة بناء تطبيقات الويب.
إيه هو React Server Component بالظبط؟
تخيل إن عندك (components) بتتقسم لنوعين:
- components بتشتغل على السيرفر فقط
- components بتشتغل على البراوزر فقط
RSC هو نظام جديد من React بيخليك تقدر تكتب الـcomponent وتحدد هو هيشتغل فين: في المتصفح ولا على السيرفر.
// ده مكون سيرفر - بيشتغل على السيرفر
// مفيش حاجة خاصة مطلوبة، لأن السيرفر هو الديفولت
async function UserProfile({ userId }) {
// هنا نقدر نوصل للداتابيز على طول
// لاحظ إننا بنستخدم async/await عادي
const user = await db.users.findById(userId);
const posts = await db.posts.findByUser(userId);
return (
<div>
<h1>{user.name}</h1>
<p>{user.bio}</p>
{/* هنا بنستخدم مكون تاني من السيرفر */}
<UserStats userId={userId} />
{/* وهنا بنستخدم مكون من المتصفح */}
<ClientFollowButton userId={userId} />
</div>
);
}
// ده مكون متصفح - بيشتغل في البراوزر
// لازم نكتب "use client" في الأول
"use client"
function ClientFollowButton({ userId }) {
// هنا نقدر نستخدم hooks لأننا في المتصفح
const [isFollowing, setIsFollowing] = useState(false);
return (
<button onClick={() => {
setIsFollowing(!isFollowing);
// هنا نقدر نعمل طلب للسيرفر
updateFollow(userId, !isFollowing);
}}>
{isFollowing ? 'Unfollow' : 'Follow'}
</button>
);
}
مميزات مهمة في RSC:
- Zero-Bundle Size: Server Components مش بتزود حجم الـJS bundle
- Automatic Code Splitting: بيقسم الكود تلقائياً بطريقة ذكية
- Direct Backend Access: وصول مباشر للداتابيز والـAPIs على السيرفر
- Better Security: الكود الحساس بيفضل على السيرفر
- Enhanced Performance: تحسين الأداء عن طريق تقليل الـJavaScript
Best Practices للاستخدام:
- استخدم Server Components للـdata fetching والـcomplex computations
- استخدم Client Components للـinteractivity والـbrowser APIs
- اعمل تقسيم منطقي للـcomponents حسب المسؤولية
- استفد من الـstreaming للـlarge data sets
الفرق بين Server Components و Client Components
Server Components:
- بتتنفذ على السيرفر بس وبتبعت HTML جاهز
- مفيش JavaScript بيتحمل على البراوزر (Zero Bundle Size)
- ممكن تعمل async/await مباشرة للـdata fetching
- تقدر توصل للداتابيز وفايل سيستم بأمان كامل
- مينفعش تستخدم useState أو useEffect (Server-side only)
- مثالية للـSEO وتحسين الأداء
- بتدعم الـstreaming والـsuspense
- ممكن تستخدم أي مكتبات Node.js مباشرة
- أسرع في الـFirst Contentful Paint (FCP)
Client Components:
- لازم تبدأ بـ ‘use client’ directive
- بتدعم كل الـReact Hooks (useState, useEffect, etc)
- مثالية للـinteractive features
- بتقدر تستخدم Browser APIs (localStorage, navigator, etc)
- بتدعم Event Listeners والـuser interactions
- ممكن تستخدم مكتبات الـanimation والـUI المتقدمة
- بتحتاج hydration عشان تشتغل
ليه مينفعش تشغل Server Components لواحدها ولازم تتعامل جوا framework زي next.js أو remix أو غيرهم؟
تخيل معايا إن React Server Components زي محرك سيارة متقدم جداً، لكن المحرك ده محتاج أنظمة كتير عشان يشتغل: نظام وقود، نظام تبريد، نظام كهرباء، وغيرهم. React نفسه مش مصمم يوفر الأنظمة دي.
أولاً: ليه مينفعش أستخدم RSC لوحده؟
// الـServerComponent محتاجة بنية تحتية معقدة
async function ServerComponent() {
const data = await db.fetch(); // ⚠️ مين هينفذ الكود ده؟
return <div>{data}</div>; // ⚠️ إزاي هنحول ده ل HTML؟
}
// محتاجين نظام خاص للتعامل مع الطلبات
async function handleRequest(request) {
// ⚠️ محتاجين:
// 1. نظام راوتنج
// 2. نظام تحميل للـComponent
// 3. نظام تحويل RSC Payload
// 4. نظام تنسيق بين السيرفر والكلاينت
// كل ده مش موجود في ريأكت العادي
}
// محتاجين طريقة للربط بين الكلاينت والسيرفر
"use client"
function ClientComponent() {
// ⚠️ إزاي هنتواصل مع الـServer Component؟
return <div>Client Side</div>;
}
المتطلبات الأساسية اللي مش موجودة في React العادي:
نظام خاص للسيرفر 🖥️
Runtime Environment
- بيئة Node.js متكاملة
- دعم للـTypeScript
- إدارة الـprocess والـthreads
نظام راوتنج متطور
// مثال للراوتنج المتقدم
app/
├── products/
│ ├── [id]/
│ │ └── page.tsx // /products/123
│ └── page.tsx // /products
└── layout.tsx // Layout عام
- معالجة الطلبات بذكاء
// مثال لمعالجة متقدمة للطلبات
async function handleRequest(req) {
const { method, headers, body } = req;
// دعم للـstreaming
// معالجة الـcache
// التعامل مع الـerrors
}
- نظام تحميل متطور 🚀
// تحميل تلقائي حسب الحاجة
import dynamic from 'next/dynamic';
const DynamicComponent = dynamic(() => import('./Heavy'));
تحويل متقدم للـHTML
- دعم للـSSR
- تحسين الـSEO
- تحسين الـperformance
إدارة الموارد
- تحسين الصور تلقائياً
- تحميل الـfonts بذكاء
- إدارة الـassets
بروتوكول اتصال متكامل 🔄
- نظام تواصل ثنائي
// مثال للتواصل بين السيرفر والكلاينت
async function ServerComponent() {
const data = await fetch('/api/data');
return <ClientComponent initialData={data} />;
}
نقل البيانات والـstate
- مزامنة تلقائية
- تعامل مع الـerrors
- دعم للـreal-time updates
مزامنة ذكية
- Optimistic Updates
- Background Sync
- Offline Support
تخيل إنك عايز تبني بيت؟ React العادي بيديك الطوب والأسمنت (الـcomponents والـstate Management)، لكن RSC محتاج:
- أساسات (سيرفر)
- هيكل معدني (نظام راوتنج)
- شبكة كهرباء (نظام اتصال)
- شبكة مياه (إدارة البيانات)
ليه Next.js مهم؟
Next.js بيوفر كل المتطلبات دي جاهزة:
// في Next.js، ده كل اللي محتاجه عشان أستخدم RSC
// app/page.js
async function HomePage() {
// Next.js بيوفر:
// - سيرفر جاهز
// - نظام راوتنج
// - نظام تحميل للـComponent
// - ربط تلقائي بين الكلاينت والسيرفر
const data = await db.fetch();
return (
<div>
<ServerComponent data={data} />
<ClientComponent />
</div>
);
}
// component سيرفر - بيشتغل على طول
async function ServerComponent({ data }) {
const moreData = await fetchMore();
return <div>{moreData}</div>;
}
// component كلاينت - Next.js بيعرف يتعامل معاه تلقائي
"use client"
function ClientComponent() {
const [state, setState] = useState();
return <button onClick={() => setState()}>Click</button>;
}
إزاي أستخدم RSC في React؟
- إتأكد من إنك بتستخدم React 19
- Project Structure
src/
├── components/
│ ├── server/ # مكونات السيرفر
│ │ └── *.server.tsx # استخدام .tsx للدعم الأفضل للـ TypeScript
│ └── client/ # مكونات العميل
│ └── *.client.tsx
├── lib/
│ ├── api/ # معالجات API
│ ├── db/ # أدوات قاعدة البيانات
│ └── types/ # تعريفات TypeScript
└── app/ # مسارات التطبيق
- إضافة بعض الإعدادات في ملف package.json:
{
"scripts": {
"dev": "node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
},
"dependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"express": "^4.18.2",
"compression": "^1.7.4",
"ws": "^8.13.0"
}
}
- إنشاء ملف server.js في الـroot من المشروع:
import express from 'express';
import { createServer } from 'http';
import { renderToPipeableStream } from 'react-dom/server';
import { WebSocketServer } from 'ws';
import compression from 'compression';
import App from './src/App.server';
// إنشاء تطبيق Express
const app = express();
const httpServer = createServer(app);
// إعدادات الخادم
app.use(express.json());
app.use(compression());
// معالجة طلبات HTTP
app.get('/*', async (req, res) => {
try {
const { pipe } = renderToPipeableStream(
,
{
bootstrapScripts: ['/client.js'],
onShellReady() {
res.setHeader('content-type', 'text/html');
pipe(res);
},
onError(error) {
console.error('خطأ في التقديم:', error);
res.status(500).send(`
عذراً، حدث خطأ في الخادم
يرجى المحاولة مرة أخرى لاحقاً
`);
}
}
);
} catch (error) {
console.error('خطأ غير متوقع:', error);
res.status(500).send('حدث خطأ غير متوقع');
}
});
// إعداد WebSocket للتحديثات في الوقت الفعلي
const wsServer = new WebSocketServer({ server: httpServer });
wsServer.on('connection', (socket) => {
console.log('تم الاتصال بـ WebSocket');
socket.on('message', (message) => {
// معالجة الرسائل الواردة
console.log('رسالة واردة:', message);
});
socket.on('close', () => {
console.log('تم إغلاق اتصال WebSocket');
});
});
// تشغيل الخادم
const PORT = process.env.PORT || 3000;
httpServer.listen(PORT, () => {
console.log(`الخادم يعمل على المنفذ ${PORT}`);
});
- تعديل الـcomponents:
// App.server.tsx - server component
import { Suspense } from 'react';
import { DataDisplay } from './components/server/DataDisplay.server';
import { ClientComponent } from './components/client/ClientComponent.client';
interface Data {
id: number;
title: string;
}
async function fetchData(): Promise<Data[]> {
// محاكاة جلب البيانات
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 1, title: 'عنصر 1' },
{ id: 2, title: 'عنصر 2' },
]);
}, 1000);
});
}
export default async function App() {
const data = await fetchData();
return (
<div>
<h1>تطبيق React Server Components</h1>
<Suspense fallback={<div>جارِ التحميل...</div>}>
<DataDisplay data={data} />
</Suspense>
<ClientComponent />
</div>
);
}
// client.jsx - client component
'use client';
import { useState } from 'react';
export function ClientComponent() {
const [count, setCount] = useState(0);
return (
<div>
<button
onClick={() => setCount(count + 1)}
className="btn-primary"
>
عدد النقرات: {count}
</button>
</div>
);
}
- تعديل ملف index.js ليتعامل مع Server Components:
import { hydrateRoot } from 'react-dom/client';
import App from './App.server';
hydrateRoot(document.getElementById('root'), <App />);
في كام نقطة مهمة محتاج تعرفها
- امتداد ملفات Server Components يجب أن يكون
.server.tsx
أو.server.jsx
- امتداد ملفات client Components يجب أن يكون
.client.tsx
أو.client.jsx
- ملفات Client Components يجب أن تبدأ بـ
'use client'
- لا يمكن استخدام hooks مثل useState في Server Components
- يمكنك استخدام async/await مباشرة في Server Components
- إتأكد من إنك تهندل الأخطاء بشكل صح try/catch
Rsc Payload
الفكرة الأساسية: بص، فريق React كان عندهم مشكلة: إزاي يبعتوا مكونات React من السيرفر للكلاينت بطريقة مرنة وفعالة. المشكلة إن JSX مش ينفع يتبعت على طول كـ JSON، لأنه فيه functions وحاجات معقدة.
الحل اللي وصلوله: قرروا يعملوا فورمات خاص (زي لغة جديدة) يسموه RSC Protocol
. الفورمات ده عبارة عن سلسلة من التعليمات، كل تعليمة ليها معنى معين.
شكل الـ Payload:
M1:{"id":"./src/Home.server.js","chunks":["client.js"],"name":"Home"}
J0:["$","div",null,{"children":["$","h1",null,{"children":"مرحباً بكم"}]}]
- السطر الأول M1 ده تعريف للموديول
- السطر التاني J0 ده وصف للـ JSX
مثال تفصيلي للـ RSC Payload
// 1. لما السيرفر يستلم طلب
async function handleRequest(request) {
// بنجيب البيانات من الداتابيز
const data = await db.fetch();
// بنحول المكون لـ RSC Payload
const stream = await renderToStream(
<App data={data} />
);
// بنبعت الـ Payload كـ stream
return stream;
}
// 2. الـ Payload بيتكون من أجزاء
const ExamplePayload = [
// تعريف الموديول
'M1:{"id":"./App.server.js","chunks":["main.js"]}',
// وصف الـ JSX
'J0:["$","div",null,{"children":[',
'"$","h1",null,{"children":"العنوان"}',
']}]',
// البيانات
'S1:{"name":"أحمد","age":25}'
];
// 3. في الكلاينت، بيتم التحليل
function processPayload(chunk) {
const [type, content] = chunk.split(':');
switch(type) {
case 'M1': // موديول
loadModule(JSON.parse(content));
break;
case 'J0': // JSX
parseJSX(JSON.parse(content));
break;
case 'S1': // بيانات
processData(JSON.parse(content));
break;
}
}
إزاي بيشتغل؟
- لما بتطلب صفحة، السيرفر بيبدأ يجهز الرد على طول
- بيبعت الـ HTML الأساسي الأول
- بعدين بيبدأ يبعت الـ RSC Payload كـ stream
- المتصفح بيستقبل الـ chunks دي ويحللها واحدة واحدة
- كل chunk بتضيف أو بتحدث حتة في الصفحة
مميزات التصميم ده:
- Streaming: مش محتاجين نستنى كل البيانات تجهز
- Progressive Hydration: الصفحة بتشتغل تدريجياً
- Selective Hydration: بنفعل بس المكونات اللي محتاجين نتفاعل معاها
- مرونة في التحديث: ممكن نحدث أي جزء من غير ما نعمل refresh للصفحة كلها
ليه التصميم ده مهم؟
- بيحل مشكلة الـ Waterfall: مش لازم نستنى كل حاجة تجهز قبل ما نبدأ نعرض
- تحسين الأداء: الصفحة بتظهر أسرع للمستخدم
- توفير الموارد: بنحمل بس اللي محتاجينه
تخيل كأنه زي المطعم:
- الويتر (السيرفر) مش بيستنى المطبخ يجهز كل الطلبات
- بيجيب كل طبق ما يجهز (streaming)
- الزبون (المتصفح) يقدر يبدأ ياكل على طول من غير ما يستنى كل الطلبات
- لو في طلب جديد، بيجيبه من غير ما يشيل الطلبات اللي موجودة