0Pricing
Frontend Academy · درس

أنماط واجهات المستخدم الفورية

طبّق التحديثات المتفائلة لتوفير استجابة فورية، واستخدم قوائم الانتظار المحلية عند عدم الاتصال، وقارن البيانات الواردة لتحديث العناصر المتغيرة فقط في واجهة المستخدم

أنماط واجهات المستخدم الفورية درس مجاني في Frontend Academy على CoddyKit. هذا هو الدرس 4 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Frontend Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Frontend Academy 4 دروس في المجموع.

الوقت الفعلي يعني تجربة استخدام تبدو فورية

لا يقتصر الوقت الفعلي على السرعة، بل يعني أيضًا الاستجابة وإمكانية التنبؤ وتحمل زمن الاستجابة. وتشمل الأنماط الأساسية ثلاثة أمور: التحديثات التفاؤلية، ووضع العمليات في قائمة محلية، وإجراء الفروقات بذكاء.

التحديثات التفاؤلية

حدّث واجهة المستخدم فورًا عند تنفيذ المستخدم لإجراء ما، قبل أن يؤكده الخادم. واسترجع الحالة السابقة إذا رفض الخادم الإجراء. فهذا يجعل التطبيقات تبدو فورية.

async function likePost(id) {
  // 1. Optimistically update UI:
  setLikes(l => ({ ...l, [id]: (l[id] || 0) + 1 }));
  setLiked(prev => ({ ...prev, [id]: true }));

  try {
    await fetch(`/api/posts/${id}/like`, { method: 'POST' });
  } catch (err) {
    // 2. Rollback on failure:
    setLikes(l => ({ ...l, [id]: (l[id] || 1) - 1 }));
    setLiked(prev => ({ ...prev, [id]: false }));
    toast.error('Could not like — please retry');
  }
}

التحديثات التفاؤلية باستخدام معرّفات مؤقتة

بالنسبة إلى العناصر التي تُنشأ، امنحها معرّفًا مؤقتًا محليًا. واستبدله بالمعرّف الحقيقي من الخادم عند وصول الاستجابة.

async function addComment(text) {
  const tempId = `tmp-${Date.now()}`;
  setComments(c => [...c, { id: tempId, text, pending: true }]);

  try {
    const saved = await fetch('/api/comments', {
      method: 'POST',
      body: JSON.stringify({ text })
    }).then(r => r.json());

    setComments(c => c.map(m => m.id === tempId ? saved : m));
  } catch (err) {
    setComments(c => c.map(m => m.id === tempId ? { ...m, error: true } : m));
  }
}

وضع العمليات في قائمة محلية عند عدم الاتصال

عند انقطاع الشبكة، ضع العمليات في قائمة محلية وأعد تنفيذها عند عودة الاتصال. وهكذا يواصل المستخدم عمله.

const queue = JSON.parse(localStorage.getItem('queue') || '[]');

function enqueue(action) {
  queue.push(action);
  localStorage.setItem('queue', JSON.stringify(queue));
  trySend();
}

async function trySend() {
  while (queue.length && navigator.onLine) {
    const action = queue[0];
    try {
      await fetch(action.url, action);
      queue.shift();
      localStorage.setItem('queue', JSON.stringify(queue));
    } catch {
      break; // stop until online
    }
  }
}

window.addEventListener('online', trySend);

إجراء الفروقات على البيانات الواردة في الوقت الفعلي

إذا دفع الخادم القائمة بأكملها، فقارنها بالحالة الحالية وحدّث التغييرات فقط — فهذا يتجنب عمليات إعادة العرض غير الضرورية ومشكلات الرسوم المتحركة.

function applyServerSnapshot(newList, currentList) {
  const current = new Map(currentList.map(i => [i.id, i]));
  const result = newList.map(item => {
    const prev = current.get(item.id);
    if (!prev) return { ...item, _state: 'new' };
    if (prev.updatedAt !== item.updatedAt) return { ...item, _state: 'updated' };
    return prev;
  });
  return result;
}

التحديثات القائمة على الرقع

هي أفضل من اللقطات الكاملة: يرسل الخادم الحقول التي تغيّرت فقط. طبّقها تدريجيًا، فهي تستخدم نطاقًا تردديًا أقل وتُعرض بسرعة أكبر.

// Server sends: { type: 'patch', id: 42, fields: { likes: 11 } }
ws.on('message', (msg) => {
  if (msg.type === 'patch') {
    setPosts(posts => posts.map(p =>
      p.id === msg.id ? { ...p, ...msg.fields } : p
    ));
  }
});

تقييد التحديثات عالية التكرار

ترسل بعض التدفقات تحديثات عديدة في الثانية، مثل موضع الفأرة وتغيّرات أسعار الأسهم. قيّد تحديثات واجهة المستخدم إلى نحو 60 هرتز لتجنب تقطّع المتصفح.

import { throttle } from 'lodash-es';

const applyUpdate = throttle((data) => {
  setData(data);
}, 16); // ~60fps

ws.on('tick', applyUpdate);

مؤشرات الحضور

اعرض من المتصل أو الذي يكتب في الوقت الفعلي. ينشر الخادم أحداث الحضور، بينما يعرض العميل قائمة تتضمن الصور الرمزية.

ws.on('presence', ({ users }) => {
  setOnlineUsers(users);
});

ws.on('typing', ({ user, isTyping }) => {
  setTypingUsers(t => isTyping
    ? [...t.filter(u => u.id !== user.id), user]
    : t.filter(u => u.id !== user.id));
});

شريط حالة الاتصال

اعرض شريطًا بسيطًا عند عدم الاتصال أو أثناء إعادة الاتصال. وأخفِه عند اكتمال إعادة الاتصال. يتقبل المستخدمون زمن الاستجابة بدرجة أكبر بكثير عندما يرون ما يحدث.

{!isConnected && (
  <div className="connection-banner">
    Reconnecting... Your changes will sync when you're back online.
  </div>
)}

حل التعارضات

يجب أن تتعامل التطبيقات الفورية مع التعديلات المتزامنة المتعارضة. وتشمل الاستراتيجيات: انتصار الكتابة الأخيرة (بسيط لكنه يفقد البيانات)، ومتجهات الإصدارات، وOT (التحويل التشغيلي)، وCRDTs (Yjs وAutomerge).

استخدام CRDTs للتعاون

تتيح CRDTs (أنواع البيانات المنسوخة الخالية من التعارض) إجراء تعديلات تعاونية في الوقت الفعلي دون خادم مركزي. ومن مكتباتها: Yjs وAutomerge. وتستخدمها تطبيقات مثل Figma وLinear وتطبيقات شبيهة بـ Notion.

الأداء: القوائم الافتراضية

قد تطول التدفقات الفورية. استخدم القوائم الافتراضية (react-virtuoso و@tanstack/react-virtual) لعرض العناصر الظاهرة فقط — وبذلك تظل الذاكرة ووحدة المعالجة المركزية ثابتتين بغض النظر عن العدد الإجمالي للعناصر.

تحقّق سريع

ما المقصود بـ التحديث التفاؤلي في واجهة مستخدم فورية؟

مراجعة: أنماط واجهات المستخدم الفورية

تجعل التحديثات التفاؤلية التطبيقات تبدو فورية، مع استرجاع الحالة السابقة عند الفشل. استخدم معرّفات مؤقتة للعناصر التي تُنشأ. واستخدم قوائم محلية لضمان الاستمرارية أثناء عدم الاتصال. أجرِ فروقات أو طبّق رقعًا على تحديثات الخادم لتجنب إعادة العرض. قيّد التدفقات عالية التكرار. اعرض الحضور، مثل الاتصال والكتابة، وأشرطة حالة الاتصال. استخدم CRDTs (Yjs وAutomerge) للتعديلات التعاونية. واستخدم القوائم الافتراضية للقوائم الفورية الطويلة.

الأسئلة الشائعة

هل درس «أنماط واجهات المستخدم الفورية» مجاني؟

نعم — نص درس «أنماط واجهات المستخدم الفورية» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Frontend Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Frontend Academy 4 دروس في المجموع.

ماذا ستتعلم في «أنماط واجهات المستخدم الفورية»؟

طبّق التحديثات المتفائلة لتوفير استجابة فورية، واستخدم قوائم الانتظار المحلية عند عدم الاتصال، وقارن البيانات الواردة لتحديث العناصر المتغيرة فقط في واجهة المستخدم تتمرن على Frontend Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Frontend Academy؟

لا تُشترط خبرة سابقة. Frontend Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 4 من أصل 4.

كم من الوقت يستغرق درس «أنماط واجهات المستخدم الفورية»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Frontend Academy هذا؟

نعم. كل درس في Frontend Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. WebSocket API: open وmessage وclose وerror
  2. دمج Socket.io Client
  3. Server-Sent Events للبث أحادي الاتجاه
  4. أنماط واجهات المستخدم الفورية
← العودة إلى Frontend Academy