العودة للرئيسية
الدرس السادس

البرمجة غير المتزامنة

فهم Callbacks و Promises و Async/Await

50 دقيقة متقدم الفصل الثاني

ما هي البرمجة غير المتزامنة؟

في Node.js، معظم العمليات تتم بشكل غير متزامن (Asynchronous)، مما يعني أن الكود لا ينتظر انتهاء عملية معينة قبل المتابعة إلى الكود التالي.

لماذا البرمجة غير المتزامنة؟

  • عدم حظر التطبيق (Non-blocking)
  • أداء أفضل وسرعة استجابة عالية
  • التعامل مع عدة طلبات في نفس الوقت
  • استخدام أمثل لموارد النظام

الطريقة الأولى: Callbacks

Callbacks هي الطريقة الكلاسيكية للتعامل مع الكود غير المتزامن:

const fs = require('fs'); // قراءة ملف بشكل غير متزامن fs.readFile('data.txt', 'utf8', (err, data) => { if (err) { console.error('حدث خطأ:', err); return; } console.log('محتوى الملف:', data); }); console.log('هذا السطر سيُطبع قبل قراءة الملف');

مشكلة Callback Hell

عند استخدام عدة Callbacks متداخلة، يصبح الكود صعب القراءة والصيانة (Callback Hell أو Pyramid of Doom)

الطريقة الثانية: Promises

Promises توفر طريقة أفضل وأوضح للتعامل مع الكود غير المتزامن:

const fs = require('fs').promises; // قراءة ملف باستخدام Promise fs.readFile('data.txt', 'utf8') .then(data => { console.log('محتوى الملف:', data); return fs.readFile('data2.txt', 'utf8'); }) .then(data2 => { console.log('محتوى الملف الثاني:', data2); }) .catch(err => { console.error('حدث خطأ:', err); }); // إنشاء Promise مخصص function delay(ms) { return new Promise(resolve => { setTimeout(resolve, ms); }); } delay(2000) .then(() => console.log('مرت ثانيتان'));

الطريقة الثالثة: Async/Await (الأفضل!)

async/await هي أحدث وأسهل طريقة للتعامل مع الكود غير المتزامن:

const fs = require('fs').promises; // استخدام async/await async function readFiles() { try { const data1 = await fs.readFile('data.txt', 'utf8'); console.log('الملف الأول:', data1); const data2 = await fs.readFile('data2.txt', 'utf8'); console.log('الملف الثاني:', data2); return 'تمت قراءة جميع الملفات'; } catch (err) { console.error('حدث خطأ:', err); throw err; } } readFiles() .then(result => console.log(result)) .catch(err => console.error(err));

مميزات Async/Await

  • كود أسهل في القراءة والفهم
  • معالجة أخطاء أبسط باستخدام try/catch
  • يشبه الكود المتزامن العادي
  • سهولة debugging

مثال عملي: جلب بيانات من API

// تثبيت axios أولاً: pnpm add axios const axios = require('axios'); // طريقة 1: Promises function getUserPromise(id) { return axios.get(`https://jsonplaceholder.typicode.com/users/${id}`) .then(response => response.data) .catch(err => { console.error('خطأ في جلب المستخدم:', err.message); throw err; }); } // طريقة 2: Async/Await (الأفضل) async function getUser(id) { try { const response = await axios.get( `https://jsonplaceholder.typicode.com/users/${id}` ); return response.data; } catch (err) { console.error('خطأ في جلب المستخدم:', err.message); throw err; } } // استخدام الدالة async function main() { try { const user = await getUser(1); console.log('المستخدم:', user.name); } catch (err) { console.error('فشل:', err); } } main();

Promise.all للعمليات المتوازية

عندما تريد تنفيذ عدة عمليات غير متزامنة في نفس الوقت:

const axios = require('axios'); async function getMultipleUsers() { try { // تنفيذ جميع الطلبات معاً const results = await Promise.all([ axios.get('https://jsonplaceholder.typicode.com/users/1'), axios.get('https://jsonplaceholder.typicode.com/users/2'), axios.get('https://jsonplaceholder.typicode.com/users/3') ]); const users = results.map(r => r.data); console.log('المستخدمون:', users); return users; } catch (err) { console.error('خطأ:', err.message); } } getMultipleUsers();

Promise Methods أخرى

  • Promise.all() - ينتظر جميع Promises (يفشل إذا فشل أي منها)
  • Promise.race() - يعيد أول Promise تنتهي
  • Promise.allSettled() - ينتظر الكل (لا يفشل أبداً)
  • Promise.any() - يعيد أول Promise تنجح