لماذا بدأت المتصفحات فجأة تتحدث بلغة جديدة؟
\n\nتخيل أنك طاهٍ محترف. JavaScript هي سكينك متعددة الاستخدامات: يمكنك بها تقطيع الخبز، وتنظيف السمك، وحتى فتح العلب (مع خطر الجرح). أما WebAssembly فهو سكين ياباني احترافي لتقطيع الساشيمي. يقوم بشيء واحد فقط - التقطيع بشكل مثالي وسريع، لكنه يتطلب نهجًا خاصًا. لن تستخدمه لتقشير البطاطس، ولكن عندما تحتاج إلى تقطيع 100 حصة من التونة في دقيقة واحدة - لا يمكنك الاستغناء عنه.
\n\nفي عالم تطوير الويب، حكم ملك واحد لفترة طويلة - JavaScript. ولكن في عام 2017، ظهر لاعب جديد على الساحة: WebAssembly (Wasm). إنه ليس بديلاً لـ JS، بل شريكه القوي. اليوم سنفهم ما هو هذا المخلوق، ولماذا هو مطلوب، وكيفية ترويضه باستخدام JavaScript.
\n\nما هو WebAssembly بكلمات بسيطة؟
\n\nWebAssembly هو تنسيق تعليمات ثنائي منخفض المستوى يتم تنفيذه في المتصفح بسرعة شبه أصلية. إذا كان JavaScript نصًا يقرأه المتصفح ويفسره أثناء التنقل، فإن Wasm هو كود بايت مُجمّع جاهز يشبه الكود الآلي.
\n\nتكتب الكود بلغة C أو C++ أو Rust، وتجمعه في ملف .wasm، ثم تحمله في المتصفح مثل أي سكريبت عادي. ينفذه المتصفح مباشرة، متجاوزًا مرحلة التحليل الطويلة والترجمة الفورية (JIT) التي يمر بها JavaScript.
\n\nالميزات الرئيسية لـ WebAssembly:
\n- \n
- السرعة - تنفيذ قريب من السرعة الأصلية (أسرع من JS بمقدار 2-10 مرات في المهام الحسابية). \n
- الأمان - يعمل في بيئة معزولة (sandbox)، تمامًا مثل JS. \n
- الاكتناز - ملفات .wasm صغيرة الحجم ويتم تحميلها بسرعة. \n
- التكامل - يمكن استدعاؤه بسهولة من JavaScript والعكس. \n
لماذا نحتاج هذا إذا كان لدينا JavaScript؟
\n\nJavaScript رائع لـ 95% من المهام: التعامل مع DOM، الرسوم المتحركة، معالجة الأحداث، طلبات الخادم. ولكن هناك مهام يقصر فيها JS:
\n\n- \n
- الحسابات الثقيلة - معالجة الفيديو، العرض ثلاثي الأبعاد، محاكاة الفيزياء. \n
- الألعاب - مشاريع AAA على Unity أو Unreal Engine. \n
- الحسابات العلمية - محاكاة الديناميكيات الجزيئية، التشفير. \n
- العمل مع الوسائط - ضغط/فك ضغط الصور، ترميز/فك ترميز الصوت والفيديو. \n
في هذه السيناريوهات، يوفر WebAssembly زيادة في الأداء بعشرات المرات. وفي نفس الوقت، لا تفقد الوصول إلى واجهات برمجة تطبيقات المتصفح (من خلال غلاف JS).
\n\nكيف يعمل هذا؟ بنية بسيطة
\n\nتخيل جسرًا بين عالمين. على جانب واحد، وحدة .wasm الخاصة بك (سريعة ولكن "غبية" - لا تعرف عن DOM والأحداث). على الجانب الآخر، JavaScript (أبطأ ولكن "ذكي" - يعرف كل شيء). يتواصلان من خلال "ذاكرة" خاصة - الذاكرة الخطية لـ Wasm.
\n\nيقوم JS بتخصيص مصفوفة بايتات (ArrayBuffer)، ويمررها إلى وحدة Wasm، التي تملؤها بالبيانات، ثم يسترجع JS النتيجة. هذا يشبه تمرير صندوق ثقيل عبر نافذة - لا تنقل كل عنصر على حدة، بل تمرر الصندوق بأكمله مرة واحدة.
\n\nنكتب مثالًا عمليًا: تسريع حساب المضروب (Factorial)
\n\nلنقارن الأداء في مهمة كلاسيكية - حساب المضروب. أولاً، سننفذه بلغة JavaScript النقية، ثم بلغة C، مُجمّعة إلى Wasm.
\n\n1. إصدار JavaScript (العادي)
\n\n// factorial.js\nfunction factorialJS(n) {\n let result = 1;\n for (let i = 2; i <= n; i++) {\n result *= i;\n }\n return result;\n}\n\n// اختبار\nconsole.time('JS');\nfor (let i = 0; i < 100000; i++) {\n factorialJS(20);\n}\nconsole.timeEnd('JS'); // ~15-25 مللي ثانية في Chrome\n\n\n2. كود C الذي سنجمعه إلى Wasm
\n\nأولاً نكتب بلغة C:
\n\n// factorial.c\nint factorial(int n) {\n int result = 1;\n for (int i = 2; i <= n; i++) {\n result *= i;\n }\n return result;\n}\n<