دمج WebAssembly وJavaScript في Node.js: دليل شامل

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

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

ابدأ الدورة

مقدمة إلى WebAssembly ودوره في Node.js



WebAssembly (WASM) هو تنسيق تعليمات ثنائي يسمح بتنفيذ كود مكتوب بلغات C و C++ و Rust وغيرها بأداء قريب من الأداء الأصلي، مباشرة في بيئة JavaScript. في نظام Node.js البيئي، يفتح WebAssembly إمكانيات فريدة: من العمليات الحسابية عالية الأداء إلى تشغيل خوارزميات معالجة البيانات المعقدة التي لم تكن متاحة سابقًا للغات المفسرة.



في هذه المقالة، سنشرح كيفية دمج WebAssembly في تطبيق Node.js، وسنستعرض أمثلة عملية لتحميل واستدعاء وحدات WASM، بالإضافة إلى مناقشة تحسين الأداء. ستتعلم كيفية استخدام WASM لتسريع الأجزاء الحرجة من الكود مع الحفاظ على بساطة التطوير باستخدام JavaScript.



أساسيات العمل مع WebAssembly في Node.js



تجميع وتحميل وحدة WASM



الخطوة الأولى هي الحصول على الملف الثنائي لـ WebAssembly. عادةً ما يتم تجميعه من C/C++ باستخدام Emscripten أو من Rust عبر wasm-pack. بالنسبة لـ Node.js، يمكننا تحميل ملفات .wasm مباشرة عبر fs.readFileSync أو عبر WebAssembly API.



مثال على تحميل وحدة من ملف module.wasm:



const fs = require('fs');const path = require('path');

async function loadWasmModule(filePath) { const wasmBuffer = fs.readFileSync(path.resolve(__dirname, filePath)); const wasmModule = await WebAssembly.instantiate(wasmBuffer); return wasmModule.instance.exports;}

// الاستخدام(async () => { const wasm = await loadWasmModule('module.wasm'); console.log(wasm.add(5, 3)); // 8})();


لاحظ أننا نستخدم WebAssembly.instantiate الذي يعيد كائنًا يحتوي على الدوال المُصدرة. الطريقة البديلة هي WebAssembly.instantiateStreaming التي تقوم بتحميل الوحدة بشكل تدفقي، وهو مفيد للملفات الكبيرة.



استيراد الدوال ومتغيرات البيئة



أحيانًا تتطلب وحدات WASM استيراد دوال JavaScript (على سبيل المثال، للطباعة على الكونسول أو العمل مع الذاكرة). لهذا الغرض، نستخدم المعامل الثاني importObject:



const importObject = {    env: {        js_log: (msgPtr, len) => {            const msg = new TextDecoder().decode(                new Uint8Array(wasmMemory.buffer, msgPtr, len)            );            console.log(msg);        },        memory: new WebAssembly.Memory({ initial: 256 })    }};

async function loadWithImports() { const wasmBuffer = fs.readFileSync('module.wasm'); const wasmModule = await WebAssembly.instantiate(wasmBuffer, importObject); return wasmModule.instance.exports;}


هنا نقوم بتمرير الذاكرة والدالة js_log التي يمكن لكود WASM استدعاءها. هذه هي الآلية الأساسية للتفاعل بين البيئتين.



أمثلة عملية لاستخدام WASM في Node.js



مثال 1: العمليات الحسابية عالية الأداء



لنفترض أن لدينا دالة بلغة C لحساب أرقام فيبوناتشي:



// fibonacci.cint fib(int n) {    if (n <= 1) return n;    return fib(n-1) + fib(n-2);}


بعد التجميع إلى WASM (عبر Emscripten: emcc fibonacci.c -o fibonacci.wasm -s WASM=1 -s EXPORTED_FUNCTIONS='["_fib"]') يمكننا استدعاؤها من Node.js:



async function testFibonacci() {    const wasm = await loadWasmModule('fibonacci.wasm');    const n = 40;    console.time('WASM fib');    const result = wasm.fib(n);    console.timeEnd('WASM fib');    console.log(`Fib(${n}) = ${result}`);}

testFibonacci();


قارن هذا مع تطبيق JavaScript الخالص — ستكون نسخة WASM أسرع بمقدار 2-5 مرات للعمليات الحسابية التكرارية.



مثال 2: معالجة الصور



WebAssembly مناسب تمامًا للعمل مع البكسلات. لننشئ وحدة لتحويل الصورة إلى تدرج رمادي:



// grayscale.cvo

المدونات

توصيات الكتب