Operasi asinkron jarang berdiri sendiri; satu langkah sering membutuhkan hasil langkah sebelumnya, misalnya mengambil nama produk baru menghitung panjang namanya, atau mengambil harga baru menentukan ongkir. Komposisi task adalah praktik menyusun langkah-langkah itu menjadi satu alur utuh. C# menyediakan dua cara utama: await berantai di dalam method asinkron, dan sambungan eksplisit lewat method ContinueWith.
Dua Cara Merangkai #
awaitberantai: setiap langkah menunggu langkah sebelumnya; alur terbaca dari atas ke bawah seperti kode sinkron, dan compiler yang menyusun kelanjutannya.ContinueWith: pemanggil melampirkan kelanjutan pada sebuah task; kelanjutan menerima task sebelumnya sebagai argumen dan dapat mengembalikan task baru untuk dirangkai lebih lanjut.
await berantai adalah pilihan default karena paling mudah dibaca. ContinueWith berguna ketika kelanjutan perlu disusun secara dinamis oleh kode lain.
Contoh: Alur Hitung Total Keranjang #
Kode berikut merangkai dua pola: lanjutan ContinueWith pada satu task, dan pipeline await untuk menghitung total belanja:
static async Task<string> AmbilNamaProdukAsync()
{
await Task.Delay(40);
return "Kopi Gayo";
}
static async Task<int> AmbilHargaAsync()
{
await Task.Delay(30);
return 85000;
}
static async Task<int> HitungOngkirAsync(int harga)
{
await Task.Delay(30);
return harga >= 50000 ? 0 : 20000;
}
static async Task<int> HitungTotalKeranjangAsync()
{
int harga = await AmbilHargaAsync();
int ongkir = await HitungOngkirAsync(harga);
return harga + ongkir;
}
// Pemanggil:
Task<string> ambil = AmbilNamaProdukAsync();
Task<int> hitungPanjang = ambil.ContinueWith(t =>
{
Console.WriteLine($"Lanjutan menerima: {t.Result}");
return t.Result.Length;
});
int panjang = await hitungPanjang;
Console.WriteLine($"Panjang nama produk: {panjang}");
int total = await HitungTotalKeranjangAsync();
Console.WriteLine($"Total keranjang: Rp{total}");Output yang Dihasilkan:
Lanjutan menerima: Kopi Gayo
Panjang nama produk: 9
Total keranjang: Rp85000Mari kita bedah komposisinya:
ambil.ContinueWith(t => ...): kelanjutan terlampir pada task nama produk; badan lambda baru berjalan setelahAmbilNamaProdukAsyncselesai.t.Resultdi dalam lanjutan: aman diakses karena task sebelumnya sudahRanToCompletion; lambda mengembalikan panjang nama, yaitu 9 karakter.await hitungPanjang: pemanggil mengeluarkan hasil kelanjutan dari objekTask<int>yang dirangkai.HitungTotalKeranjangAsync: pipeline dua langkah; nilaihargamengalir keHitungOngkirAsync, dan ongkir 0 muncul karena harga 85000 melewati batas 50000.
Merangkai berurutan sudah tertangani. Bab berikutnya membahas menjalankan banyak task secara serentak dengan Task.WhenAll dan Task.WhenAny.