0Pricing
Scala for Backend Engineering & Functional Programming · درس

تركيب العمليات غير المتزامنة

تعلّم ربط عدة `Futures` ودمجها باستخدام أساليب مثل `map` و`flatMap` وتعبيرات `for`

تركيب العمليات غير المتزامنة درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 2 من أصل 3. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 3 دروس في المجموع.

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

تساعدنا Futures على تشغيل المهام دون حظر البرنامج الرئيسي. لكن ماذا لو كانت نتيجة إحدى المهام مطلوبة لمهمة أخرى، أو احتجنا إلى دمج نتائج عدة مهام؟

هنا يأتي دور تركيب Futures. سنتعلم كيفية ربط هذه العمليات غير المتزامنة ودمجها، مما يجعل تعليمات Scala البرمجية لديكم أكثر قوة واستجابة.

`map`: تحويل نتيجة Future

تُستخدم الدالة map عندما يكون لديكم Future وتريدون تحويل نتيجته الناجحة إلى قيمة أخرى. ستُطبَّق دالة التحويل التي تقدمونها بعد اكتمال Future بنجاح.

  • تعيد دائمًا Future جديدًا.
  • وهي مناسبة تمامًا للتحويلات البسيطة والمتزامنة على نتيجة غير متزامنة.

`map` قيد التنفيذ (التعليمة البرمجية)

نحصل هنا على رقم من Future ثم نضاعفه باستخدام map. لا يحدث التحويل إلا بعد انتهاء Future الأولي.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val originalFuture: Future[Int] = Future {
      Thread.sleep(100) // Simulate work
      10
    }

    val doubledFuture: Future[Int] = originalFuture.map(value => value * 2)

    val result = Await.result(doubledFuture, 1.second)
    println(s"Doubled value: $result")
  }
}

`flatMap`: ربط Futures

أحيانًا تحتاج النتيجة الناجحة لـ Future إلى بدء Future آخر. هنا تتألق flatMap، إذ إنها «تسطّح» Future من Future (Future[Future[T]]) إلى Future[T] واحد.

  • استخدموها عندما تعيد دالة التحويل Future.
  • وهي أساسية لتنفيذ العمليات غير المتزامنة بالتتابع.

`flatMap` قيد التنفيذ (التعليمة البرمجية)

نجلب معرّف مستخدم، ثم نستخدم ذلك المعرّف لجلب تفاصيل المستخدم. كل خطوة هي عملية غير متزامنة تعيد Future. تضمن flatMap تنفيذ الخطوات بالتتابع.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    def fetchUserId(): Future[Int] = Future {
      Thread.sleep(50)
      123
    }

    def fetchUserDetails(userId: Int): Future[String] = Future {
      Thread.sleep(100)
      s"User $userId details"
    }

    val userDetailsFuture: Future[String] = fetchUserId().flatMap { userId =>
      fetchUserDetails(userId)
    }

    val result = Await.result(userDetailsFuture, 1.second)
    println(s"Details: $result")
  }
}

`map` في مقابل `flatMap`: الفرق الأساسي

من الشائع الخلط بين map وflatMap. تذكّروا ما يلي:

  • map: تعيد دالتكم قيمة عادية، مثل Int أو String. ينتج عن Future[A].map(A => B) قيمة Future[B].
  • flatMap: تعيد دالتكم Future آخر، مثل Future[Int] أو Future[String]. ينتج عن Future[A].flatMap(A => Future[B]) قيمة Future[B].

تُستخدم flatMap لربط العمليات غير المتزامنة، بينما تُستخدم map لتحويل نتيجة غير متزامنة بطريقة متزامنة.

تعبيرات `for`: ربط أنيق

توفر تعبيرات for في Scala صياغة واضحة وسهلة القراءة لربط العمليات التي تتضمن map وflatMap. وهي مجرد تسهيل نحوي؛ أي إن المترجم يحولها إلى سلسلة من استدعاءات map وflatMap وfilter.

عندما تكون لديكم عدة عمليات Future تعتمد إحداها على الأخرى، تجعل تعبيرات for التعليمات البرمجية تبدو شبه متزامنة.

تعليمة تعبير `for` البرمجية

يستخدم هذا المثال تعبير for لربط منطق جلب معرّف المستخدم وتفاصيله نفسه الذي رأيناه مع flatMap. لاحظوا مدى نظافة مظهره!

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    def fetchUserId(): Future[Int] = Future {
      Thread.sleep(50)
      123
    }

    def fetchUserName(userId: Int): Future[String] = Future {
      Thread.sleep(100)
      s"Alice (ID: $userId)"
    }

    val userFuture: Future[String] = for {
      id <- fetchUserId()
      name <- fetchUserName(id)
    } yield name

    val result = Await.result(userFuture, 1.second)
    println(s"User name: $result")
  }
}

`zip`: دمج النتائج المستقلة

ماذا لو كان لديكم اثنان مستقلان من Future وتريدون دمج نتائجهما بعد اكتمالهما معًا؟ إن الدالة zip مناسبة تمامًا لذلك. فهي تأخذ Future آخر وتعيد Future جديدًا يحتوي على زوج (Tuple) من نتائجهما الناجحة.

يعمل كلا الـFuture بالتزامن، وتنتظر zip انتهاءهما معًا.

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val futureA = Future {
      Thread.sleep(100)
      "Hello"
    }

    val futureB = Future {
      Thread.sleep(50)
      "World"
    }

    val combinedFuture: Future[(String, String)] = futureA.zip(futureB)

    val (greeting, subject) = Await.result(combinedFuture, 1.second)
    println(s"$greeting $subject!")
  }
}

اختبار سريع: تركيب Futures

تأملوا مقطع تعليمات Scala البرمجية التالي. ما القيمة النهائية التي ستتم طباعتها؟

import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration._

object Main {
  def main(args: Array[String]): Unit = {
    val f1 = Future { 5 }
    val f2 = f1.map(x => x + 2)
    val f3 = f2.flatMap(y => Future { y * 3 })

    val result = Await.result(f3, 1.second)
    println(result)
  }
}

مراجعة: ربط المهام غير المتزامنة

لقد تعلمتم طرقًا فعالة لتركيب Future في Scala:

  • map: تحول النتيجة الناجحة لـ Future إلى قيمة جديدة.
  • flatMap: تربط بين اثنين من Future، بحيث تُستخدم نتيجة الأول لبدء الثاني.
  • تعبيرات for: توفر صياغة واضحة تبدو متزامنة لربط flatMap وmap.
  • zip: تدمج نتائج اثنين مستقلين من Future في صفيفة.

تُعد هذه الأدوات أساسية لبناء تطبيقات Scala غير متزامنة سريعة الاستجابة وفعالة!

الأسئلة الشائعة

هل درس «تركيب العمليات غير المتزامنة» مجاني؟

نعم — نص درس «تركيب العمليات غير المتزامنة» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 3 دروس في المجموع.

ماذا ستتعلم في «تركيب العمليات غير المتزامنة»؟

تعلّم ربط عدة `Futures` ودمجها باستخدام أساليب مثل `map` و`flatMap` وتعبيرات `for` تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 2 من أصل 3.

كم من الوقت يستغرق درس «تركيب العمليات غير المتزامنة»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. مقدمة إلى Futures وPromises
  2. تركيب العمليات غير المتزامنة
  3. معالجة الأخطاء في Futures
← العودة إلى Scala for Backend Engineering & Functional Programming