0Pricing
Scala for Backend Engineering & Functional Programming · 강의

비동기 연산 조합

`map`, `flatMap`, `for` 컴프리헨션 같은 메서드를 사용해 여러 `Future`를 연결하고 결합하는 방법을 배웁니다.

비동기 연산 조합은(는) CoddyKit의 무료 Scala for Backend Engineering & Functional Programming 강의입니다. 이것은 3개 중 2번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Scala for Backend Engineering & Functional Programming 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Scala for Backend Engineering & Functional Programming 강의에는 총 3개의 강의가 포함되어 있습니다.

이 강의의 일부는 아직 번역되지 않았으며 영어로 표시됩니다.

Why Chain Async Operations?

Futures help us run tasks without blocking the main program. But what if one task's result is needed for another, or we need to combine results from multiple tasks?

This is where composing Futures comes in handy. We'll learn how to chain and combine these asynchronous operations, making your Scala code more powerful and responsive.

`map`: Transform a Future's Result

The map method is used when you have a Future and you want to transform its successful result into another value. The transformation function you provide will be applied once the Future completes successfully.

  • It always returns a new Future.
  • It's perfect for simple, synchronous transformations on an asynchronous result.

`map` in Action (Code)

Here, we get a number from a Future and then double it using map. The transformation happens only after the initial Future finishes.

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`: Chaining Futures

Sometimes, the successful result of one Future needs to kick off another Future. This is where flatMap shines. It "flattens" a Future of a Future (Future[Future[T]]) into a single Future[T].

  • Use it when your transformation function returns a Future.
  • It's essential for sequential asynchronous operations.

`flatMap` in Action (Code)

We fetch a user ID, then use that ID to fetch user details. Each step is an asynchronous operation returning a Future. flatMap ensures they run in sequence.

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` vs. `flatMap`: Key Difference

It's common to confuse map and flatMap. Remember:

  • map: Your function returns a regular value (e.g., Int, String). Future[A].map(A => B) results in Future[B].
  • flatMap: Your function returns another Future (e.g., Future[Int], Future[String]). Future[A].flatMap(A => Future[B]) results in Future[B].

flatMap is for chaining async operations, while map is for transforming an async result synchronously.

`for` Comprehensions: Elegant Chaining

Scala's for comprehensions provide a clean, readable syntax for chaining operations that involve map and flatMap. They are purely syntactic sugar, meaning the compiler translates them into a series of map, flatMap, and filter calls.

When you have multiple dependent Future operations, for comprehensions make the code look almost synchronous.

`for` Comprehension Code

This example uses a for comprehension to chain the same user ID and details fetching logic we saw with flatMap. Notice how much cleaner it looks!

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`: Combining Independent Results

What if you have two independent Futures and want to combine their results once both are complete? The zip method is perfect for this. It takes another Future and returns a new Future that holds a pair (a Tuple) of their successful results.

Both futures run concurrently, and zip waits for both to finish.

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!")
  }
}

Quick Check: Composing Futures

Consider the following Scala code snippet. What will be the final value printed?

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)
  }
}

Recap: Chaining Async Tasks

You've learned powerful ways to compose Scala Futures:

  • map: Transforms a Future's successful result into a new value.
  • flatMap: Chains two Futures where the result of the first is used to start the second.
  • for comprehensions: Provide a clean, synchronous-looking syntax for flatMap and map chains.
  • zip: Combines the results of two independent Futures into a tuple.

These tools are crucial for building responsive and efficient asynchronous applications in Scala!

자주 묻는 질문

“비동기 연산 조합” 강의는 무료인가요?

네 — “비동기 연산 조합” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Scala for Backend Engineering & Functional Programming 강의 전체를 잠금 해제할 수 있습니다. Scala for Backend Engineering & Functional Programming 강의에는 총 3개의 강의가 포함되어 있습니다.

“비동기 연산 조합”에서 뭘 배우나요?

`map`, `flatMap`, `for` 컴프리헨션 같은 메서드를 사용해 여러 `Future`를 연결하고 결합하는 방법을 배웁니다. 브라우저에서 직접 실행하는 실습 코드로 Scala for Backend Engineering & Functional Programming을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Scala for Backend Engineering & Functional Programming을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Scala for Backend Engineering & Functional Programming은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 3개 중 2번째 강의입니다.

“비동기 연산 조합” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Scala for Backend Engineering & Functional Programming 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Scala for Backend Engineering & Functional Programming 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Future와 Promise 입문
  2. 비동기 연산 조합
  3. Future의 오류 처리
← Scala for Backend Engineering & Functional Programming(으)로 돌아가기