جافا سكريبت ضد الجيجابايت: كيف يهضم المتصفح البيانات الضخمة

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

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

ابدأ الدورة

عندما لا يكون المتصفح لعبة، بل مركز بيانات

\n\n

لقد اعتدنا على أن جافا سكريبت يعيش في صندوق رمل المتصفح: الرسوم المتحركة، النقرات، النماذج. ولكن ماذا لو أخبرتك أنه باستخدام JS الخالص يمكنك معالجة ملف CSV بحجم 500 ميجابايت، ورسم بياني بـ 100,000 نقطة دون تعليق علامة التبويب؟ هذا ليس خيالاً علمياً، بل استخدام صحيح لـ معالجة البيانات الضخمة على جافا سكريبت.

\n

في هذه المقالة، سأوضح لك كيفية العمل مع كميات كبيرة من البيانات مباشرة في المتصفح - بدون خادم خلفي، بدون Python، بدون نسخ الجيجابايتات إلى الخادم. ستتعرف على البث المباشر، Web Workers، تحسين الذاكرة، والمكتبات التي تحول المتصفح إلى معالج بيانات مصغر. هيا بنا!

\n\n

لماذا تقتل المعالجة "الساذجة" للبيانات الأداء

\n

تخيل: تقوم بتحميل ملف CSV بحجم 300 ميجابايت وتكتب:

\n
const data = await response.json(); // ❌ خطأ فادح
\n

ماذا يحدث؟ يحاول JS تحليل الملف بأكمله في الذاكرة العاملة. إذا كان لدى المستخدم 4 جيجابايت من ذاكرة الوصول العشوائي - سينهار المتصفح. حتى على جهاز قوي، سيبدأ جامع القمامة في "التباطؤ"، وسيتجمد الواجهة لمدة دقيقة.

\n

القاعدة رقم 1: لا تقم بتحميل كل شيء دفعة واحدة. تتطلب البيانات الضخمة على جافا سكريبت معالجة تدفقية (streaming) وتقسيمها إلى أجزاء.

\n\n

بث البيانات: قراءة الملف قطعة قطعة

\n

تسمح واجهة برمجة تطبيقات المتصفح FileReader بقراءة الملف على أجزاء. ولكن الأكثر ملاءمة هو ReadableStream. مثال: معالجة ملف JSON كبير سطراً بسطر.

\n\n

مثال: بث JSON باستخدام NDJSON

\n

تنسيق NDJSON (كل سطر هو كائن JSON منفصل) مثالي للبيانات الضخمة. إليك كيفية قراءته كتيار:

\n
async function* streamJSON(file) {\n  const stream = file.stream();\n  const reader = stream.getReader();\n  const decoder = new TextDecoder();\n  let buffer = '';\n\n  while (true) {\n    const { done, value } = await reader.read();\n    if (done) break;\n    buffer += decoder.decode(value, { stream: true });\n    const lines = buffer.split('\\n');\n    buffer = lines.pop(); // الباقي في المخزن المؤقت\n    for (const line of lines) {\n      if (line.trim()) yield JSON.parse(line);\n    }\n  }\n}\n\n// الاستخدام\nfor await (const obj of streamJSON(selectedFile)) {\n  processRow(obj); // معالجة كائن واحد في كل مرة\n}\n
\n

الذاكرة لا تكاد تزيد - نحتفظ بسطر واحد فقط في الذاكرة. هذا النهج هو أساس معالجة البيانات الضخمة باستخدام جافا سكريبت في المشاريع الحقيقية.

\n\n

Web Workers: لا نعلق الواجهة

\n

حتى البث المباشر يتم تنفيذه في الخيط الرئيسي. إذا كانت الحسابات معقدة - ستتجمد واجهة المستخدم. الحل: Web Workers. هذا خيط منفصل حيث يمكنك معالجة الجيجابايتات دون تأخير.

\n\n

إنشاء Worker لمعالجة CSV

\n

كود العامل (worker.js):

\n
self.onmessage = async function(e) {\n  const { file, chunkSize } = e.data;\n  const reader = new FileReaderSync(); // قراءة متزامنة - مسموح للعامل\n  let offset = 0;\n  const results = [];\n\n  while (offset < file.size) {\n    const blob = file.slice(offset, offset + chunkSize);\n    const text = reader.readAsText(blob);\n    const lines = text.split('\\n');\n    for (const line of lines) {\n      if (line.trim()) results.push(parseCSVLine(line));\n    }\n    offset += chunkSize;\n    // إرسال النتيجة الوسيطة\n    self.postMessage({ type: 'chunk', data: results.splice(0, results.length) });\n  }\n  self.postMessage({ type: 'done' });\n};\n\nfunction parseCSVLine(line) {\n  const [name, age, city] = line.split(',');\n  return { name, age: parseInt(age), city };\n}\n
\n

الخيط الرئيسي:

\n
const worker = new Worker('worker.js');\nworker.postMessage({ file: csvFile, chunkSize: 1024 * 1024 }); // أجزاء بحجم 1 ميجابايت\n\nworker.onmessage = (e) => {\n  if (e.data.type === 'chunk') {\n    updateUI(e.data.data); // تحديث الجدول/الرسم البياني بسلاسة\n  }\n};\n
\n

الآن تبقى الواجهة سريعة الاستجابة، حتى لو كنا نعالج 2 جيجابايت من البيانات. هذه هي التقنية الأساسية لـ b

المدونات

توصيات الكتب