التزامن وتعدد الخيوط في TypeScript: المستوى المتقدم
\n\nفي تطوير الويب الحديث وبرمجة الخوادم، يعتبر أداء التطبيقات واستجابتها أمرًا بالغ الأهمية. TypeScript، كونه طبقة علوية فوق JavaScript، ورث نموذج التنفيذ أحادي الخيط (Event Loop). ومع ذلك، لحل المهام كثيفة الاستخدام للموارد (معالجة الصور، التشفير، الحسابات المعقدة)، فإن عدم التزامن وحده لا يكفي. على المستوى المتقدم، يحتاج المطور إلى فهم كيفية تنظيم تعدد الخيوط الحقيقي والعمل الآمن مع الذاكرة المشتركة. في هذه المقالة، سنشرح الآليات الرئيسية: Web Workers (المتصفح)، Worker Threads (Node.js)، SharedArrayBuffer و Atomics.
\n\n1. Web Workers: التوازي في المتصفح
\n\nWeb Workers هي الطريقة الأساسية لتشغيل الكود في خيط منفصل في بيئة المتصفح. لا يملك Worker إمكانية الوصول إلى DOM، لكن يمكنه تنفيذ عمليات حسابية ثقيلة دون حظر الخيط الرئيسي (UI).
\n\nيتطلب إنشاء Worker في TypeScript تجميع ملف منفصل. لنلق نظرة على مثال: حساب أعداد فيبوناتشي الكبيرة.
\n\nملف worker.ts (يتم تجميعه إلى worker.js):
\n// worker.ts\nself.onmessage = (event: MessageEvent<number>) => {\n const n = event.data;\n const fib = (num: number): number => {\n if (num <= 1) return num;\n return fib(num - 1) + fib(num - 2);\n };\n const result = fib(n);\n self.postMessage(result);\n};\n\nالملف الرئيسي main.ts:
\n// main.ts\nconst worker = new Worker(new URL('./worker.js', import.meta.url));\n\nworker.postMessage(40);\n\nworker.onmessage = (event: MessageEvent<number>) => {\n console.log(`النتيجة: ${event.data}`); // الإخراج بعد الانتهاء\n worker.terminate();\n};\n\nworker.onerror = (error) => {\n console.error('خطأ في Worker:', error.message);\n};\n\nملاحظات مهمة:
\n- \n
- يتم تشغيل Worker في خيط منفصل، لكنه لا يملك إمكانية الوصول إلى المتغيرات العامة للخيط الرئيسي. \n
- يتم نقل البيانات عن طريق النسخ (الاستنساخ الهيكلي). للبيانات الكبيرة، استخدم Transferable objects (مثل ArrayBuffer). \n
- بالنسبة لـ TypeScript، يجب تحديد الأنواع في الرسائل لتجنب أخطاء وقت التشغيل. \n
2. Worker Threads: تعدد الخيوط في Node.js
\n\nبالنسبة لبيئة الخادم Node.js، فإن النظير لـ Web Workers هو وحدة worker_threads. تسمح بإنشاء خيوط معزولة بذاكرة خاصة بها (V8 isolate). هذا مثالي للعمليات المكثفة لوحدة المعالجة المركزية (CPU)، مثل التجزئة أو تحليل JSON.
مثال: إنشاء Worker لتجزئة كلمة المرور (worker.ts):
\n// crypto-worker.ts\nimport { parentPort, workerData } from 'worker_threads';\nimport { createHash } from 'crypto';\n\nif (parentPort) {\n const { password, salt } = workerData;\n const hash = createHash('sha256')\n .update(password + salt)\n .digest('hex');\n parentPort.postMessage(hash);\n}\n\nالملف الرئيسي (main.ts):
\n// main.ts\nimport { Worker } from 'worker_threads';\nimport path from 'path';\n\nfunction hashPassword(password: string, salt: string): Promise<string> {\n return new Promise((resolve, reject) => {\n const worker = new Worker(path.resolve(__dirname, 'crypto-worker.js'), {\n workerData: { password, salt }\n });\n\n worker.on('message', resolve);\n worker.on('error', reject);\n worker.on('exit', (code) => {\n if (code !== 0) reject(new Error(`انتهى Worker بالرمز ${code}`));\n });\n });\n}\n\n(async () => {\n const hash = await hashPassword('mySecret', 'randomSalt');\n console.log(`التجزئة: ${hash}`);\n})();\n\nالاختلافات الرئيسية عن Web Workers:
\n- \n
- يعمل في Node.js، مع إمكانية الوصول إلى نظام الملفات والعملية. \n
- نقل البيانات عبر