async — Coroutine Builder di Kotlin yang menjalankan korutin dan mengembalikan objek Deferred<T> untuk mendapatkan hasil operasi asinkron. async memungkinkan eksekusi paralel beberapa tugas dan mengagregasi hasilnya melalui await(). Menurut panduan JetBrains, 2024, async adalah cara yang lebih disukai untuk mengatur komputasi paralel dalam korutin.
Poin Utama
async — adalah fungsi ekstensi CoroutineScope yang membuat korutin dengan pengembalian hasil. Tidak seperti launch, async mengembalikan Deferred<T> — objek yang mewakili nilai masa depan. Korutin yang dijalankan melalui async dieksekusi secara konkuren dengan korutin lain, memungkinkan paralelisasi komputasi.
async digunakan ketika hasil operasi asinkron diperlukan untuk pemrosesan lebih lanjut: memuat data dari beberapa sumber, pemrosesan batch koleksi, permintaan paralel ke berbagai API. Deferred dibuat segera, dan hasilnya tersedia setelah korutin selesai.
import kotlinx.coroutines.*
suspend fun String.delayedValue(): String {
delay(1000L)
return this
}
fun main() = runBlocking {
val deferred: Deferred<String> = async { "Hello".delayedValue() }
println(deferred.await())
}
Sintaks async mirip dengan launch: parameter CoroutineContext, CoroutineStart dan blok suspend yang sama. Perbedaannya ada pada tipe yang dikembalikan — Deferred<T> sebagai ganti Job, di mana T adalah tipe hasil yang dikembalikan oleh ekspresi terakhir blok.
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T>
Deferred<T> — antarmuka yang mewarisi Job dan menambahkan metode await(), getCompleted(), getCompletionExceptionOrNull(). await() adalah fungsi suspend dan hanya dapat dipanggil di dalam korutin atau fungsi suspend lainnya. getCompleted() — metode non-pemblokiran yang melempar pengecualian jika korutin belum selesai.
Keuntungan utama async adalah kemampuan untuk menjalankan tugas secara paralel. Alih-alih menunggu sekuensial setiap operasi (waktu total = jumlah waktu), async menjalankan korutin secara bersamaan, mengurangi waktu total menjadi waktu operasi terpanjang.
Skenario tipikal — memuat profil pengguna, pengaturannya, dan riwayat pesanan dengan tiga permintaan async paralel. Setelah ketiganya selesai, hasilnya digabungkan menjadi satu model data.
suspend fun loadUserDashboard(userId: String): Dashboard = coroutineScope {
val profile = async { api.getProfile(userId) }
val settings = async { api.getSettings(userId) }
val orders = async { api.getRecentOrders(userId) }
Dashboard(
profile = profile.await(),
settings = settings.await(),
orders = orders.await()
)
}
Fungsi coroutineScope menjalankan korutin anak dan menunggu penyelesaiannya sebelum mengembalikan hasil. Seluruh blok dieksekusi secara paralel, bukan sekuensial.
Deferred mendukung beberapa metode untuk bekerja dengan hasil. Selain await(), tersedia metode untuk memeriksa status, mendapatkan nilai jadi, dan agregasi beberapa Deferred melalui fungsi utilitas Kotlin Coroutines.
| Metode | Deskripsi | Suspend? |
|---|---|---|
| await() | Menjeda korutin hingga hasil diperoleh | Ya |
| getCompleted() | Mengembalikan hasil jika korutin selesai (jika tidak Exception) | Tidak |
| getCompletionExceptionOrNull() | Mengembalikan pengecualian saat kesalahan atau null | Tidak |
| isCompleted | Memeriksa apakah korutin telah selesai | Tidak |
Untuk agregasi daftar Deferred digunakan awaitAll() — fungsi yang menjeda eksekusi hingga semua Deferred dalam koleksi selesai. Jika setidaknya satu berakhir dengan kesalahan, awaitAll() melempar pengecualian.
suspend fun <T> loadAll(requests: List<suspend () -> T>): List<T> {
return coroutineScope {
val deferreds = requests.map { async { it() } }
deferreds.awaitAll()
}
}
Pilihan antara async dan launch tergantung pada apakah hasil eksekusi korutin diperlukan. launch mengembalikan Job dan cocok untuk operasi fire-and-forget, async mengembalikan Deferred dan digunakan untuk tugas yang mengembalikan data. Dari segi sintaks dan parameter, pembangunnya identik.
Aturan penting: jangan gunakan async untuk fire-and-forget. Jika hasil korutin tidak diperlukan, gunakan launch. async membuat overhead untuk pembuatan Deferred, yang tidak dapat dibenarkan dalam skenario seperti itu.
Di Android, async digunakan untuk operasi paralel di dalam ViewModel dan UseCases. Skenario umum: memuat profil dan feed berita secara bersamaan, mendapatkan cuaca dari beberapa layanan cuaca, sinkronisasi data batch dengan server.
class HomeViewModel : ViewModel() {
fun loadHomeScreen() {
viewModelScope.launch {
val userData = async(Dispatchers.IO) { repository.getUserData() }
val newsFeed = async(Dispatchers.IO) { repository.getNewsFeed() }
val notifications = async(Dispatchers.IO) { repository.getNotifications() }
val state = HomeState(
user = userData.await(),
news = newsFeed.await(),
unread = notifications.await()
)
_uiState.update { state }
}
}
}
Disarankan untuk membungkus grup async dalam coroutineScope atau supervisorScope untuk isolasi kesalahan. supervisorScope memungkinkan kelanjutan eksekusi korutin async lainnya meskipun terjadi kesalahan di salah satunya — berguna untuk operasi non-kritis.
Pertanyaan yang Sering Diajukan
Bisa, tapi tidak berguna. async tanpa await() menjalankan korutin, tetapi hasilnya hilang. Jika hasil tidak diperlukan, gunakan launch — ia tidak membuat Deferred dan lebih efisien dalam hal memori dan kinerja.
Pengecualian di dalam async disimpan di Deferred. Panggilan await() melemparkan pengecualian ini. Untuk memeriksa tanpa melempar, gunakan getCompletionExceptionOrNull(). Saat menggunakan coroutineScope, kesalahan membatalkan semua korutin anak.
awaitAll() — fungsi ekstensi untuk Iterable<Deferred<T>> yang menjeda korutin hingga semua Deferred selesai. Mengembalikan daftar hasil. Jika setidaknya satu Deferred berakhir dengan kesalahan, ia melemparkan pengecualian dan membatalkan sisanya.
Ya. async adalah fungsi ekstensi CoroutineScope, terikat pada scope. GlobalScope.async membuat korutin tanpa ikatan siklus hidup — dapat berjalan tanpa batas. Di Android, GlobalScope tidak disarankan karena risiko kebocoran memori.
Jumlahnya ditentukan oleh dispatcher: Dispatchers.IO mendukung hingga 64 thread bersamaan, Dispatchers.Default — berdasarkan jumlah inti CPU. Untuk operasi massal, gunakan paralelisme terbatas melalui Semaphore atau mapNotNull dengan awaitAll.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga