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

آخر تحديث: 2026-10-13

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


دوال غير متزامنة:async/await Promise.allSettled Promise.race Promise.all setTimeout Promise catch then

1. متزامن مقابل غير متزامن

متزامن: الكود ينفذ سطر بسطر — السطر التالي ينتظر انتهاء الحالي. مثل الوقوف في الصف — تنتظر حتى ينتهي الشخص أمامك.

غير متزامن: عمليات معينة (طلبات الشبكة، المؤقتات، إدخال/إخراج الملفات) تبدأ دون عرض الكود اللاحق. عندما تنتهي، يتم إخطارك عبر استدعاء أو Promise.

HTML
<script>
console.log('1');
setTimeout(function() {
  console.log('2');
}, 1000);
console.log('3');
</script>

ترتيب الإخراج هو 1 → 3 → 2. setTimeout غير متزامن — الاستدعاء ينفذ بعد ثانية واحدة دون عرض console.log('3').



الاستدعاءات هي النمط الأساسي للبرمجة غير المتزامنة — تمرير دالة كمعامل، وتُستدعى عندما تكتمل العملية غير المتزامنة.

▶ مثال: استخدام أساسي للاستدعاء

▶ جرّب الكود

(1) جحيم الاستدعاءات (Callback Hell)

عندما تعتمد العمليات غير المتزامنة على بعضها تسلسلياً، تتداخل الاستدعاءات أعمق وأعمق — هذا هو "جحيم الاستدعاءات" سيئ السمعة.

HTML
<script>
getUser(function(user) {
  getOrders(user.id, function(orders) {
    getOrderDetail(orders[0].id, function(detail) {
      getItems(detail.itemId, function(items) {
        console.log('4 مستويات عميقة — أضف تعقيداً أكثر ويصبح غير مقروء');
      });
    });
  });
});
</script>
💡 تلميح: جحيم الاستدعاءات يبدو كهرم أفقي — يصعب قراءته وصيانته. اخترع Promises لحل هذا.



2. Promise

Promise هو كائن يمثل النتيجة النهائية لعملية غير متزامنة. لديه ثلاث حالات:

الحالة الوصف
pending قيد التنفيذ، لا نتيجة بعد
fulfilled اكتملت بنجاح، النتيجة متاحة
rejected فشلت، الخطأ متاح

بمجرد انتقال Promise من pending إلى fulfilled أو rejected، لا تتغير مرة أخرى — مثل سهم أُطلق، لا يمكن استدعاؤه.

(1) إنشاء Promise

HTML
<script>
const promise = new Promise(function(resolve, reject) {
  // عملية غير متزامنة
  // استدعاء resolve(result) عند النجاح
  // استدعاء reject(error) عند الفشل
});
</script>

(2) then / catch / finally

HTML
<script>
promise
  .then(function(result) { console.log(result); })   // ينفذ عند النجاح
  .catch(function(error) { console.error(error); })    // ينفذ عند الفشل
  .finally(function() { console.log('تم'); });         // ينفذ بغض النظر
</script>

▶ مثال: محاكاة طلب بـ Promise

▶ جرّب الكود

(3) التسلسل

then نفسها تُرجع Promise، لذا يمكنك تسلسل الاستدعاءات — جحيم الاستدعاءات يصبح خطاً مباشراً.

HTML
<script>
fetchUser()
  .then(function(user) { return fetchOrders(user.id); })
  .then(function(orders) { return fetchDetail(orders[0].id); })
  .then(function(detail) { console.log(detail); })
  .catch(function(err) { console.error(err); });
</script>
💡 تلميح: catch واحدة في نهاية التسلسل تلتقط الأخطاء من أي خطوة — لا تحتاج catch بعد كل then.



3. async / await

async/await هو سكر صناعي فوق Promises — يجعل الكود غير المتزامن يبدو متزامناً، مما يحسن القراءة بشكل كبير.

▶ مثال: إعادة كتابة الطلب أعلاه بـ async/await

▶ جرّب الكود
💡 تلميح: مقارنة بالاستدعاءات، async/await يحول "خذ رقماً وانتظر" إلى "ابقَ في الصف دون مغادرة" — تدفق الكود مباشقر والقراءة ترتفع بشكل كبير.

(1) معالجة الأخطاء

async/await يستخدم try/catch لمعالجة الأخطاء — نفس النمط المستخدم مع الكود المتزامن.

HTML
<script>
async function loadAll() {
  try {
    const user = await fetchUser();
    const orders = await fetchOrders(user.id);
    console.log(orders);
  } catch (err) {
    console.error('حدث خطأ ما:', err);
  }
}
</script>


4. Promise.all و Promise.race

الطريقة الوصف
Promise.all([p1, p2, p3]) ينجح فقط إذا نجح الجميع؛ يفشل بمجرد فشل واحد
Promise.race([p1, p2, p3]) يستخدم نتيجة أيهما يحل أولاً (نجاح أو فشل)

▶ مثال: طلبات متزامنة مع Promise.all

▶ جرّب الكود
💡 تلميح: Promise.all مثل عشاء جماعي — يجب أن يصل الجميع قبل أن تأكل. Promise.race مثل سباق — من ينتهي أولاً يفوز. استخدم all للطلبات المستقلة لتسريع الأشياء، و race عندما يكون لديك عدة مصادر مرآة وتريد الأسرع.



دوال غير متزامنة:async/await Promise.allSettled Promise.race Promise.all setTimeout Promise catch then

❓ أسئلة شائعة

س هل يمكن استخدام await في دالة عادية؟
ج لا. await يمكن استخدامه فقط داخل دالة async. استخدام await في دالة عادية يسبب خطأ صيغة. await المسطح مدعوم في الوحدات، لكن الدعم في المتصفحات يختلف.
س ماذا يحدث إذا فشل أحد Promises في Promise.all؟
ج Promise.all يرفض فوراً بالخطأ الأول. Promises الأخرى لا تزال تُنفذ، لكن نتائجها تُتجاهل. إذا كنت بحاجة إلى "الجميع يحل بغض النظر عن النتيجة"، استخدم Promise.allSettled.
س ماذا تُرجع دالة async؟
ج دالة async تُرجع دائماً Promise. حتى لو return 42، في الواقع تُرجع Promise.resolve(42). لذا يمكنك استخدام .then() لاستهلاك النتيجة.

📖 ملخص

📝 تمارين

  1. أساسي: استخدم Promise + setTimeout لمحاكاة تأخير ثانيتين، ثم اطبع "تم" عند النجاح.
  2. متوسط: أعد كتابة أعلاه بـ async/await وأضف معالجة أخطاء try/catch.
  3. تحدي: استخدم Promise.all لإطلاق 3 طلبات محاكاة بتأخيرات مختلفة (1 ثانية/2 ثانية/3 ثانية) متزامنة، ثم احسب واعرض الوقت الكلي المنقضي عندما تكتمل جميعها.
Web-Tutorial.com

فريق Web-Tutorial التقني

منصة دروس برمجية يديرها عدة مطورين. كل درس يتم كتابته ومراجعته بواسطة مطورين متخصصين في المجال. نعمل على ضمان دقة وموثوقية المحتوى — إذا لاحظت أي مشكلة، فيرجى إخبارنا.

100%