suspend function: apa itu, sintaks dan cara kerja di coroutine

Penulis: IT Sectr Diterbitkan: 2026-06-22 Waktu membaca: 9 mnt

Suspend function — adalah fungsi dengan modifier suspend yang dapat menangguhkan eksekusinya tanpa memblokir thread dan melanjutkannya nanti di coroutine yang sama. Menurut JetBrains Kotlin Docs, 2025, fungsi suspend adalah blok bangunan fundamental coroutine, menyediakan asinkronisitas tanpa callback. Setiap fungsi suspend dikompilasi menjadi state machine berbasis Continuation, yang memungkinkan pengelolaan titik penangguhan secara efisien.

Poin Penting

  • Suspend — kata kunci Kotlin yang menandai fungsi sebagai dapat ditangguhkan (asinkron)
  • Continuation — parameter tersembunyi yang ditambahkan compiler ke setiap fungsi suspend untuk menyimpan status
  • Titik penangguhan — tempat pemanggilan fungsi suspend lain di mana coroutine dapat berhenti tanpa memblokir
  • State machine — representasi internal fungsi suspend, di mana setiap titik penangguhan adalah state terpisah
  • Panggilan hanya dari coroutine — fungsi suspend hanya dapat dipanggil dari fungsi suspend lain atau dari launch/async

Apa itu suspend function di Kotlin?

Suspend function — adalah fungsi yang dideklarasikan dengan kata kunci suspend yang dapat menangguhkan eksekusi di satu atau lebih titik tanpa memblokir thread. Setiap pemanggilan fungsi suspend di dalam fungsi suspend lain adalah titik penangguhan potensial.

kotlin
suspend fun fetchUserData(): User {
    val response = httpClient.get("/user")
    return parser.parse(response)
}

Compiler Kotlin menerjemahkan fungsi tersebut menjadi state machine. Setiap titik penangguhan (pemanggilan fungsi suspend lain) menjadi sebuah state (label). Thread saat ini dibebaskan di antara state, dan setelah operasi yang ditunggu selesai, eksekusi dilanjutkan dari state berikutnya.

Sejarah kemunculan

Fungsi suspend muncul di Kotlin 1.3 (tahun 2018) bersama dengan coroutine sebagai fitur eksperimental dan menjadi stabil di Kotlin 1.5 (tahun 2021). Sebelumnya, asinkronisitas di Kotlin/Java disediakan melalui callback, RxJava, dan CompletableFuture. Fungsi suspend menawarkan alternatif dengan sintaks linier dan manajemen thread otomatis.

Bagaimana cara kerja fungsi suspend: Continuation dan state machine

Memahami struktur internal fungsi suspend adalah kunci untuk bekerja dengan benar dengan coroutine. Tidak seperti fungsi biasa, setiap fungsi suspend dikompilasi menjadi kelas dengan antarmuka Continuation.

Continuation — parameter tersembunyi

Compiler Kotlin menambahkan parameter bertipe Continuation di akhir setiap parameter fungsi suspend. Continuation berisi:

  • context — CoroutineContext (dispatcher, job, elemen konteks)
  • resumeWith — metode untuk melanjutkan eksekusi dengan hasil atau pengecualian
  • label — indeks state saat ini di state machine

State machine dengan contoh

Misalkan kita memiliki fungsi suspend dengan dua pemanggilan ke fungsi suspend lain:

kotlin
suspend fun process() {
    val a = stepOne()
    val b = stepTwo(a)
    println(b)
}

Compiler mengubahnya menjadi state machine dengan label:

kotlin
// Representasi kode yang dihasilkan secara sederhana
fun process(cont: Continuation<Unit>): Any? {
    val cont = cont as ProcessContinuation
    when (cont.label) {
        0 -> {
            cont.label = 1
            if (stepOne(cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        1 -> {
            cont.label = 2
            val a = cont.result as TypeA
            if (stepTwo(a, cont) == COROUTINE_SUSPENDED) return COROUTINE_SUSPENDED
        }
        2 -> {
            println(cont.result)
            Unit
        }
    }
}

Pengamatan penting: jika fungsi mengembalikan COROUTINE_SUSPENDED, thread saat ini dibebaskan. Ketika operasi asinkron selesai, Continuation.resumeWith dipanggil, dan state machine melanjutkan dari label berikutnya.

Sintaks fungsi suspend: deklarasi dan pemanggilan

Deklarasi fungsi suspend tidak berbeda dengan fungsi biasa, kecuali kata kunci suspend sebelum fun. Hanya ada satu batasan: fungsi suspend hanya dapat dipanggil dari coroutine atau fungsi suspend lain.

Deklarasi dasar

kotlin
suspend fun delayAndReturn(ms: Long): String {
    delay(ms)
    return "Done after ${ms}ms"
}

Dalam contoh ini, delay juga merupakan fungsi suspend yang menangguhkan coroutine selama jumlah milidetik yang ditentukan tanpa memblokir thread. Setelah penundaan, eksekusi dilanjutkan.

Pemanggilan dari coroutine

kotlin
fun main() = runBlocking {
    val result = delayAndReturn(1000)
    println(result)
}

runBlocking membuat jembatan antara dunia biasa dan coroutine. Di dalam lambda, pemanggilan fungsi suspend apa pun diperbolehkan.

Lambda suspend dan tipe fungsional

Kotlin mendukung versi suspend dari tipe fungsional — suspend () -> T dan suspend (A) -> B. Ini memungkinkan pengiriman lambda asinkron ke fungsi tingkat tinggi:

kotlin
suspend fun  withRetry(
    retries: Int = 3,
    block: suspend () -> T
): T {
    repeat(retries - 1) {
        try { return block() }
        catch (_: Exception) { delay(100) }
    }
    return block()
}

Fungsi withRetry menerima lambda suspend dan mengulangi eksekusinya saat terjadi kesalahan. Ini adalah pola umum untuk permintaan jaringan dengan percobaan ulang.

Perbedaan fungsi suspend dengan fungsi biasa

Perbedaan antara fungsi suspend dan biasa melampaui sekadar penambahan modifier. Mari lihat perbedaan mendasarnya.

KarakteristikFungsi biasaFungsi suspend
Thread eksekusiMemblokir thread hingga selesaiDapat membebaskan thread dan melanjutkan nanti
Parameter compilerHanya parameter yang ditentukanContinuation implisit di akhir
Panggilan dari fungsi biasaYaTidak
StackStack fisik threadState machine di heap + stack fisik antar titik
ReturnNilai langsungNilai atau COROUTINE_SUSPENDED
KinerjaOverhead minimal~beberapa nanodetik untuk state machine (Kotlin 1.9+)

Mengapa fungsi suspend tidak bisa dipanggil dari fungsi biasa

Fungsi biasa tidak memiliki Continuation — tidak ada tempat untuk menyimpan status dan melanjutkan eksekusi. Jika perlu memanggil fungsi suspend dari fungsi biasa, gunakan runBlocking (untuk pengujian) atau CoroutineScope.launch (untuk produksi dengan mempertimbangkan siklus hidup).

Contoh fungsi suspend di Android

Mari lihat tiga skenario nyata penggunaan fungsi suspend di aplikasi Android dengan Kotlin.

Contoh 1: Room DAO dengan kueri suspend

Room mendukung fungsi suspend secara langsung — kueri dijalankan di latar belakang secara otomatis:

kotlin
@Dao
interface UserDao {
    @Query("SELECT * FROM users WHERE id = :id")
    suspend fun getUser(id: Int): User?

    @Insert
    suspend fun insertUser(user: User)
}

Room secara internal menggunakan Dispatchers.IO untuk menjalankan kueri, dan hasilnya dikembalikan ke dispatcher tempat fungsi suspend dipanggil.

Contoh 2: Komposisi fungsi suspend untuk memuat layar

kotlin
class ProfileViewModel : ViewModel() {
    private val repo = ProfileRepository()

    fun loadProfile(id: String) {
        viewModelScope.launch {
            val profile = repo.getProfile(id)
            _profile.value = profile
        }
    }
}

ViewModelScope.launch membuat coroutine, di dalamnya fungsi suspend getProfile dipanggil. Setelah mendapatkan hasil, UI diperbarui di thread utama.

Contoh 3: Langkah asinkron berurutan

kotlin
suspend fun placeOrder(cart: Cart): OrderResult {
    val validated = validateCart(cart)
    val payment = processPayment(validated)
    val receipt = sendReceipt(payment)
    return receipt
}

Tiga fungsi suspend dijalankan secara berurutan. Di setiap langkah, coroutine dapat berhenti tanpa memblokir thread. Jika suatu langkah melempar pengecualian — langkah lainnya tidak dijalankan, yang melindungi dari status pesanan yang tidak valid.

Kesalahan umum saat bekerja dengan fungsi suspend

Bahkan pengembang Kotlin berpengalaman pun membuat kesalahan saat merancang fungsi suspend. Mari lihat yang paling umum.

Kesalahan 1: Panggilan memblokir di dalam suspend

Fungsi suspend tidak membuat kode secara otomatis asinkron. Thread.sleep(), InputStream.read(), dan panggilan memblokir lainnya tetap akan memblokir thread. Gunakan withContext(Dispatchers.IO) untuk membungkus operasi memblokir.

Kesalahan 2: Membuat fungsi suspend tanpa kebutuhan

Jika suatu fungsi tidak memanggil fungsi suspend lain dan tidak melakukan operasi asinkron — modifier suspend berlebihan. Ini menambah overhead pada state machine dan membatasi konteks pemanggilan. Buat fungsi suspend hanya jika fungsi tersebut benar-benar ditangguhkan.

Kesalahan 3: Mengabaikan CancellationException

Saat pembatalan coroutine, fungsi suspend melempar CancellationException. Jangan menangkapnya tanpa berpikir — Anda menghilangkan kemampuan kode pemanggil untuk menyelesaikan pembatalan dengan benar. Jika perlu melakukan operasi finalisasi, gunakan blok finally dan NonCancellable.

kotlin
suspend fun safeOperation() {
    try {
        doWork()
    } finally {
        withContext(NonCancellable) {
            cleanup()
        }
    }
}

Blok finally selalu dijalankan, termasuk saat pembatalan, dan NonCancellable memastikan pembersihan tidak terputus.

Kesalahan 4: Memanggil fungsi suspend dari callback

Fungsi suspend tidak dapat dipanggil langsung dari callback tanpa membuat coroutine. Gunakan suspendCoroutine atau suspendCancellableCoroutine untuk mengadaptasi gaya callback ke coroutine.

Pertanyaan yang Sering Diajukan

Bisakah fungsi suspend tidak memiliki titik penangguhan?

Ya, secara teknis fungsi suspend bisa tidak memanggil fungsi suspend lain. Compiler akan membuat state machine dengan satu state (label 0). Namun, fungsi seperti itu tidak memiliki manfaat praktis — ia dijalankan seperti fungsi biasa, tetapi dengan overhead. Jangan gunakan suspend tanpa kebutuhan.

Bagaimana cara men-debug fungsi suspend?

Kotlin menyediakan kotlinx-coroutines-debug — pustaka dengan DebugProbes dan alat pelacakan coroutine. Di Android Studio mulai versi Arctic Fox, ada tab Coroutines bawaan di Debugger yang menampilkan coroutine aktif, status, dan titik penangguhannya.

Apakah jumlah titik suspend memengaruhi kinerja?

Setiap titik penangguhan membuat state baru di state machine. Untuk sebagian besar aplikasi, overhead satu titik adalah satuan nanodetik (Kotlin 1.9+). Hanya jika ada puluhan ribu titik dalam satu loop, ada baiknya menggabungkan operasi atau menggunakan sequence/flow.

Apa perbedaan fungsi suspend dengan async/await di bahasa lain?

Di Kotlin, suspend adalah modifier tipe fungsi, bukan penanda nilai kembali (seperti async di C#). Fungsi suspend apa pun dapat memiliki parameter dan tipe kembali apa pun, dan pemanggilannya secara sintaks tidak berbeda dengan pemanggilan fungsi biasa — tidak ada operator await di tempat pemanggilan.

Bagaimana mengubah fungsi callback menjadi suspend?

Gunakan suspendCancellableCoroutine untuk adaptasi. Di dalamnya, Anda memberikan pendaftaran callback yang memanggil continuation.resume() dan mengembalikan token pembatalan jika callback mendukung pembatalan langganan. Ini adalah pola standar untuk membungkus API Android lama.

Kesimpulan

  • Suspend function — fungsi dengan modifier suspend yang dapat menangguhkan eksekusi tanpa memblokir thread melalui mekanisme Continuation
  • State machine — representasi internal fungsi suspend dalam bytecode Kotlin, di mana setiap titik penangguhan adalah state terpisah dengan label
  • Continuation — parameter tersembunyi yang berisi konteks coroutine dan metode resumeWith untuk melanjutkan eksekusi
  • Panggilan hanya dari coroutine — fungsi suspend tidak dapat diakses dari fungsi biasa tanpa runBlocking atau CoroutineScope
  • Operasi memblokir di dalam suspend memerlukan withContext(Dispatchers.IO) — jika tidak, thread akan diblokir
  • Room dan Retrofit mendukung fungsi suspend secara native, secara otomatis mengelola thread latar belakang
  • CancellationException — tangani pembatalan melalui finally + NonCancellable, jangan menangkap CancellationException tanpa berpikir

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.

Diskusikan proyek

Baca juga