البرمجة غير المتزامنة في JavaScript: دليل شامل للمبتدئين

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

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

ابدأ الدورة

مقدمة في البرمجة غير المتزامنة في JavaScript

\n\n

JavaScript هي لغة برمجة أحادية الخيط. وهذا يعني أنه في كل لحظة زمنية يتم تنفيذ عملية واحدة فقط. ومع ذلك، إذا تم تنفيذ جميع العمليات بشكل تسلسلي، فسيحدث "تجميد" للمتصفح عند تحميل البيانات من الخادم أو قراءة ملف. وهنا يأتي دور البرمجة غير المتزامنة.

\n\n

تسمح البرمجة غير المتزامنة بتنفيذ العمليات الطويلة (طلبات API، قراءة الملفات، المؤقتات) دون حظر سير التنفيذ الرئيسي. بدلاً من انتظار اكتمال المهمة، يستمر الكود في التنفيذ، وتتم معالجة النتيجة لاحقًا. هذا مفهوم أساسي لإنشاء تطبيقات سريعة وسريعة الاستجابة على Node.js.

\n\n

في هذا الدليل، سنشرح ثلاثة مناهج رئيسية للبرمجة غير المتزامنة: دوال الاسترجاع (Callbacks)، والوعود (Promises)، وبناء الجملة async/await. ستتعلم كيفية العمل بشكل صحيح مع الكود غير المتزامن وتجنب الأخطاء الشائعة للمبتدئين.

\n\n

1. دوال الاسترجاع (Callbacks): أساس عدم التزامن

\n\n

دالة الاسترجاع (callback) هي دالة يتم تمريرها كوسيطة لدالة أخرى ويتم استدعاؤها بعد اكتمال العملية غير المتزامنة. هذه هي أقدم وأبسط طريقة للعمل مع عدم التزامن في JavaScript.

\n\n

مثال مع setTimeout

\n\n

الدالة المدمجة setTimeout هي مثال كلاسيكي لعملية غير متزامنة. تأخذ دالة استرجاع وتأخيرًا بالمللي ثانية:

\n\n
console.log('البداية');\n\nsetTimeout(() => {\n    console.log('مرت ثانيتان');\n}, 2000);\n\nconsole.log('النهاية');\n\n// الإخراج:\n// البداية\n// النهاية\n// مرت ثانيتان
\n\n

لاحظ: "النهاية" تُطبع قبل الرسالة من دالة الاسترجاع. هذا هو عدم التزامن - الكود لا ينتظر اكتمال setTimeout.

\n\n

مشكلة "جحيم دوال الاسترجاع" (Callback Hell)

\n\n

عندما يكون لديك العديد من العمليات غير المتزامنة المتداخلة، يصبح الكود صعب القراءة. تُسمى هذه الظاهرة "جحيم دوال الاسترجاع" (Callback Hell):

\n\n
fs.readFile('file1.txt', (err, data1) => {\n    if (err) throw err;\n    fs.readFile('file2.txt', (err, data2) => {\n        if (err) throw err;\n        fs.readFile('file3.txt', (err, data3) => {\n            if (err) throw err;\n            console.log(data1, data2, data3);\n        });\n    });\n});
\n\n

من الصعب صيانة وتصحيح مثل هذا الكود. لحسن الحظ، تقدم JavaScript الحديثة حلولاً أكثر أناقة.

\n\n

2. الوعود (Promises): معالجة أنيقة لعدم التزامن

\n\n

Promise (الوعد) هو كائن يمثل نتيجة عملية غير متزامنة. يمكن أن يكون الوعد في إحدى ثلاث حالات:

\n\n
    \n
  • Pending (معلق) - الحالة الأولية، العملية لم تكتمل بعد
  • \n
  • Fulfilled (مُنجز) - اكتملت العملية بنجاح
  • \n
  • Rejected (مرفوض) - اكتملت العملية بخطأ
  • \n
\n\n

إنشاء واستخدام Promise

\n\n
const myPromise = new Promise((resolve, reject) => {\n    setTimeout(() => {\n        const success = true;\n        if (success) {\n            resolve('تم الحصول على البيانات');\n        } else {\n            reject('خطأ في الحصول على البيانات');\n        }\n    }, 2000);\n});\n\nmyPromise\n    .then(result => {\n        console.log(result); // "تم الحصول على البيانات"\n    })\n    .catch(error => {\n        console.error(error); // "خطأ في الحصول على البيانات"\n    })\n    .finally(() => {\n        console.log('اكتملت العملية');\n    });
\n\n

سلسلة الوعود (Chaining)

\n\n

يمكن ربط الوعود في سلاسل، مما يسمح بتجنب "جحيم دوال الاسترجاع":

\n\n
function readFile(filename) {\n    return new Promise((resolve, reject) => {\n        fs.readFile(filename, 'utf8', (err, data) => {\n            if (err) reject(err);\n            else resolve(data);\n        });\n    });\n}\n\nreadFile('file1.txt')\n    .then(data1 => {\                

المدونات

توصيات الكتب