أحمد حايس
الرئيسيةمن أناالدوراتالمدونةالعروض
أحمد حايس

دورات عربية متخصصة في التقنية والبرمجة والذكاء الاصطناعي.

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

تعلم أسرعوصول مباشر للدورات والمسارات من الموبايل.
تنقل أوضحالروابط الأساسية والدعم في مكان واحد بدون تشتيت.

المنصة

  • الرئيسية
  • من أنا
  • الدورات
  • العروض
  • المدونة

الدعم

  • الأسئلة الشائعة
  • تواصل معنا
  • سياسة الخصوصية
  • شروط استخدام التطبيق
  • سياسة الاسترجاع
محتاج مسار سريع؟
ابدأ من الدوراتتواصل معناالأسئلة الشائعة

© 2026 أحمد حايس. جميع الحقوق محفوظة.

الرئيسيةالدوراتالعروضالمدونةالدخول

Web Workers في JavaScript للمتوسط: شغّل عمليات ثقيلة بدون ما تجمّد المتصفح

📅 ١٠ مايو ٢٠٢٦⏱ 5 دقائق قراءة
Web Workers في JavaScript للمتوسط: شغّل عمليات ثقيلة بدون ما تجمّد المتصفح
المستوى: متوسط — يفترض إنك كاتب JavaScript حديث، فاهم Promises و async/await، وعندك مشروع شغّال على Vite أو webpack.

لو dashboard بتاعك بيتجمّد 4 ثواني كل ما المستخدم يرفع ملف CSV حجمه 80MB، المشكلة مش في حجم الملف ولا في سرعة اللاب. JavaScript بيشتغل على thread واحد، وأي عملية parsing بتقفل الـ UI كله — مفيش scroll، مفيش click، حتى الـ animation بيقف.

Web Workers بـ 30 سطر بتنقل العملية الثقيلة دي لـ thread موازي، فالـ UI يفضل سلس 60fps والمستخدم يقدر يلغي العملية لو غيّر رأيه.

Web Workers: التوازي اللي JavaScript مكنش بيعرفه

شاشات متعددة تعرض كود JavaScript يعمل بالتوازي يرمز إلى تشغيل Web Workers في خيوط منفصلة عن الـ main thread

المشكلة باختصار

JavaScript في المتصفح بيشتغل على main thread واحد. الـ thread ده مسؤول عن 4 حاجات في نفس الوقت: تنفيذ الكود، رسم الصفحة، الاستجابة للـ events (click, scroll, keyboard)، وتشغيل الـ animations.

لو دالة JavaScript بتاخد 800ms في الحساب، الـ 4 حاجات دي بتقف 800ms. المستخدم بيشوف الصفحة "متجمّدة"، وفي Chrome بيظهرله "Page Unresponsive" بعد 5 ثواني.

مثال للمبتدئ: مطعم الكاشير الواحد

تخيّل مطعم فيه كاشير واحد بيعمل كل حاجة: ياخد الطلب من العميل، يحضّر الأكل، يعمل الفاتورة، يستلم الفلوس، يرد الباقي. لو جه عميل عايز كباب — والكباب محتاج 12 دقيقة على الفحم — الكاشير هيقف 12 دقيقة قدام الفرن، والـ 18 عميل اللي ورا ميلاقوش حد يطلب منه. المطعم كله بيتجمّد لحد ما الكباب يخلص.

الحل المنطقي: تجيب طبّاخ في المطبخ. الكاشير يكتب الطلب على ورقة، يبعتها للمطبخ من الباب الجانبي، ويرجع يخدم العملاء. الطبّاخ يحضّر، وأول ما الأكل يبقى جاهز، يقول للكاشير "خد الطلب رقم 47". الكاشير ساعتها بس بيوقف ثانية يستلم.

الكاشير = main thread. الطبّاخ = Web Worker. ورقة الطلب = postMessage.

Web Worker علميًا

طبقًا لـ HTML Living Standard (قسم Web Workers)، الـ Web Worker هو script بيشتغل في خلفية المتصفح في execution context منفصل تمامًا عن الـ main thread. الفصل ده بمعنى الكلمة:

  • مفيش shared memory افتراضيًا (إلا لو استخدمت SharedArrayBuffer صراحة).
  • الـ Worker مش شايف الـ DOM ولا window ولا document.
  • التواصل بين الـ main thread والـ Worker بيتم عبر postMessage() اللي بيـ serialize البيانات (Structured Clone Algorithm).

الفصل ده هو السبب اللي بيخلّي Web Workers آمنة: مفيش race conditions على متغير مشترك زي ما بيحصل في threads بـ C++ أو Java.

5 خطوات لتشغيل Web Worker (بكود فعلي)

هنبني مثال واقعي: parsing لملف CSV 82MB فيه بيانات مبيعات (1.4 مليون صف).

الخطوة 1: اعمل ملف الـ Worker

JavaScript
// csv-worker.js
self.onmessage = (event) => {
  const { fileText } = event.data;
  const rows = fileText.split('\n');
  const result = [];

  for (let i = 1; i < rows.length; i++) {
    const cols = rows[i].split(',');
    if (cols.length < 3) continue;
    result.push({
      date: cols[0],
      product: cols[1],
      amount: parseFloat(cols[2]),
    });

    if (i % 50000 === 0) {
      self.postMessage({ type: 'progress', percent: (i / rows.length) * 100 });
    }
  }

  self.postMessage({ type: 'done', result });
};

الخطوة 2: شغّل الـ Worker من الـ main thread

JavaScript
// main.js (Vite, ESM)
const worker = new Worker(
  new URL('./csv-worker.js', import.meta.url),
  { type: 'module' }
);

document.querySelector('#file').addEventListener('change', async (e) => {
  const file = e.target.files[0];
  const text = await file.text();

  worker.postMessage({ fileText: text });
});

worker.onmessage = (event) => {
  const { type, percent, result } = event.data;
  if (type === 'progress') {
    progressBar.value = percent;
  } else if (type === 'done') {
    renderTable(result);
    worker.terminate();
  }
};

الخطوة 3: اقيس الفرق

على ملف CSV 82MB، Chrome 130، MacBook Air M2:

  • بدون Worker: UI مجمّد 4,180ms، الـ scroll مش شغّال، 0 fps خلال الـ parsing.
  • بـ Worker: UI شغّال 60fps طول الوقت، main thread واقف بس 18ms (بتاع الـ postMessage)، الـ progress bar شغّال طبيعي.

Trade-offs لازم تعرفها قبل ما تستخدمها

Web Workers مش حل سحري. كل توصية ليها ثمنها:

  1. Serialization مش مجاني. postMessage بينسخ البيانات بـ Structured Clone. لو بتبعت array فيها مليون object، النسخ نفسه بياخد 200-400ms. الـ Transferable Objects (مثل ArrayBuffer) بتنقل الملكية بدون نسخ، بس مش كل البيانات بتدعمها.
  2. مفيش DOM. الـ Worker مش هيقدر يعدّل HTML أو يقرا قيمة من input. لازم ترجّع البيانات للـ main thread وهو اللي يلمس الـ DOM.
  3. تكلفة تشغيل. فتح Worker بياخد 5-15ms ثبات. لو هتعمل عملية أصلًا بتاخد 30ms، الـ Worker بيضيع وقت أكتر مما يوفّر.
  4. Debugging أصعب. الـ stack trace في الـ Worker منفصل. لازم تفتح Sources tab في DevTools وتختار الـ Worker يدويًا.
فريق مطورين يعملون على شاشات متوازية يمثل توزيع المهام بين main thread و worker threads داخل المتصفح

أفضل حالات استخدام Web Workers

  • Parsing ملفات كبيرة: CSV, JSON, XML أكتر من 5MB.
  • Image processing: filters, resize, compression قبل الرفع.
  • Cryptography: hashing, encryption لكميات بيانات كبيرة.
  • تحليل بيانات: aggregations, sorting على آلاف الصفوف.
  • WebAssembly heavy compute: physics simulations, video encoding.

متى لا تستخدم Web Workers

الافتراض إن العملية ثقيلة فعلًا. لو الكود بتاعك:

  • بياخد أقل من 50ms على main thread → سيب الكود مكانه. الـ Worker overhead أكبر من المكسب.
  • محتاج DOM access مباشر → Worker مش هينفع. فكّر في requestIdleCallback أو تقسيم العمل لـ chunks بـ setTimeout.
  • بيتم مرة واحدة في عمر الـ session → التعقيد الإضافي مش مبرّر.
  • على بيانات حجمها أقل من 1MB والوقت أقل من 100ms → الفرق مش هيتحس بصريًا.

الـ trade-off الحقيقي: Web Worker بيشيل العبء عن main thread، بس بيضيف تعقيد في الـ build (Vite, webpack محتاجة config) وفي الـ debugging. لو dashboard بسيط بيشتغل تمام، متعقّدش الكود من غير سبب.

الخطوة التالية

افتح المشروع بتاعك، دوّر على أبطأ عملية في الـ frontend (الأغلب parsing أو filtering على مصفوفة كبيرة)، وقيس زمنها بـ performance.now(). لو طلع أكتر من 100ms، انسخ الـ template اللي فوق وحوّلها لـ Worker. لو الزمن أقل من 50ms، اتركها — التوازي مش حل لكل مشكلة.

المصادر

  • HTML Living Standard — Web Workers (WHATWG)
  • MDN — Using Web Workers
  • Structured Clone Algorithm — WHATWG
  • MDN — Transferable Objects
  • Vite Documentation — Web Workers
  • web.dev — When to use Web Workers (Surma, Google)
]]>

هل استفدت من المقال؟

اطّلع على المزيد من المقالات والدروس المجانية من نفس المسار المعرفي.

تصفّح المدونة