Łączenie operacji asynchronicznych
Naucz się łączyć i komponować wiele obiektów `Future` za pomocą metod takich jak `map`, `flatMap` i wyrażeń `for`.
Łączenie operacji asynchronicznych to bezpłatna lekcja Scala for Backend Engineering & Functional Programming na CoddyKit. To lekcja 2 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Scala for Backend Engineering & Functional Programming, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Scala for Backend Engineering & Functional Programming zawiera 3 lekcji w sumie.
Dlaczego łączyć operacje asynchroniczne?
Obiekty Future pozwalają uruchamiać zadania bez blokowania głównego programu. Co jednak zrobić, gdy wynik jednego zadania jest potrzebny innemu albo trzeba połączyć wyniki wielu zadań?
W takich sytuacjach przydaje się komponowanie obiektów Future. Nauczą się Państwo łączyć te operacje asynchroniczne w łańcuchy oraz scalać je, aby kod Scali był bardziej wydajny i responsywny.
`map`: przekształcanie wyniku obiektu Future
Metody map używa się, gdy mają Państwo obiekt Future i chcą przekształcić jego pomyślny wynik w inną wartość. Podana funkcja przekształcająca zostanie zastosowana po pomyślnym zakończeniu obiektu Future.
- Zawsze zwraca nowy obiekt
Future. - Doskonale nadaje się do prostych, synchronicznych przekształceń wyniku asynchronicznego.
`map` w działaniu (kod)
W tym przykładzie pobieramy liczbę z obiektu Future, a następnie podwajamy ją za pomocą map. Przekształcenie następuje dopiero po zakończeniu początkowego obiektu 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`: łączenie obiektów Future
Czasami pomyślny wynik jednego obiektu Future musi uruchomić kolejny obiekt Future. Właśnie w tym sprawdza się flatMap. „Spłaszcza” obiekt Future zawierający inny obiekt Future (Future[Future[T]]) do pojedynczego obiektu Future[T].
- Należy go używać, gdy funkcja przekształcająca zwraca obiekt
Future. - Jest niezbędny w sekwencyjnych operacjach asynchronicznych.
`flatMap` w działaniu (kod)
Pobieramy identyfikator użytkownika, a następnie używamy go do pobrania danych użytkownika. Każdy etap jest operacją asynchroniczną zwracającą obiekt Future. flatMap zapewnia wykonanie ich w odpowiedniej kolejności.
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` a `flatMap`: najważniejsza różnica
Często zdarza się mylić map z flatMap. Należy pamiętać:
map: Państwa funkcja zwraca zwykłą wartość (np.Int,String).Future[A].map(A => B)daje w wynikuFuture[B].flatMap: Państwa funkcja zwraca kolejny obiektFuture(np.Future[Int],Future[String]).Future[A].flatMap(A => Future[B])daje w wynikuFuture[B].
flatMap służy do łączenia operacji asynchronicznych, natomiast map — do synchronicznego przekształcania wyniku asynchronicznego.
Wyrażenia `for`: eleganckie łączenie
Wyrażenia for w Scali zapewniają przejrzystą, czytelną składnię do łączenia operacji wykorzystujących map i flatMap. Są wyłącznie cukrem składniowym, co oznacza, że kompilator tłumaczy je na serię wywołań map, flatMap i filter.
Gdy mają Państwo wiele zależnych od siebie operacji Future, wyrażenia for sprawiają, że kod wygląda niemal jak synchroniczny.
Kod wyrażenia `for`
Ten przykład wykorzystuje wyrażenie for do połączenia tej samej logiki pobierania identyfikatora użytkownika i jego danych, którą wcześniej przedstawiliśmy za pomocą flatMap. Proszę zauważyć, o ile kod jest czytelniejszy!
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`: łączenie niezależnych wyników
Co zrobić, gdy mają Państwo dwa niezależne obiekty Future i chcą połączyć ich wyniki po zakończeniu obu operacji? Metoda zip doskonale się do tego nadaje. Przyjmuje ona kolejny obiekt Future i zwraca nowy obiekt Future zawierający parę (Tuple) ich pomyślnych wyników.
Oba obiekty Future są wykonywane współbieżnie, a zip czeka na zakończenie obu.
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!")
}
}Szybkie sprawdzenie: komponowanie obiektów Future
Proszę rozważyć poniższy fragment kodu Scali. Jaka będzie końcowa wypisana wartość?
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)
}
}Podsumowanie: łączenie zadań asynchronicznych
Poznali Państwo skuteczne sposoby komponowania obiektów Future w Scali:
map: Przekształca pomyślny wynik obiektuFuturew nową wartość.flatMap: Łączy dwa obiektyFuture, wykorzystując wynik pierwszego do uruchomienia drugiego.- Wyrażenia
for: Zapewniają przejrzystą, przypominającą synchroniczną składnię dla łańcuchówflatMapimap. zip: Łączy wyniki dwóch niezależnych obiektówFuturew krotkę.
Te narzędzia mają kluczowe znaczenie przy tworzeniu responsywnych i wydajnych aplikacji asynchronicznych w Scali!
Często zadawane pytania
Czy lekcja „Łączenie operacji asynchronicznych” jest bezpłatna?
Tak — pełny tekst „Łączenie operacji asynchronicznych” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Scala for Backend Engineering & Functional Programming, przejdź na CoddyKit PRO. Kurs Scala for Backend Engineering & Functional Programming zawiera 3 lekcji w sumie.
Co nauczysz się w „Łączenie operacji asynchronicznych”?
Naucz się łączyć i komponować wiele obiektów `Future` za pomocą metod takich jak `map`, `flatMap` i wyrażeń `for`. Ćwiczysz Scala for Backend Engineering & Functional Programming z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Scala for Backend Engineering & Functional Programming?
Nie wymagamy żadnego doświadczenia. Scala for Backend Engineering & Functional Programming w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 3.
Ile czasu zajmuje lekcja „Łączenie operacji asynchronicznych”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Scala for Backend Engineering & Functional Programming?
Tak. Każda lekcja Scala for Backend Engineering & Functional Programming zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Wprowadzenie do Futures i Promises
- Łączenie operacji asynchronicznych
- Obsługa błędów w Futures