Dart Asynchronous
Secara harfiah, asynchronous berarti “tidak terjadi pada waktu yang sama”. Dalam pemrograman, ini adalah teknik untuk menjalankan operasi yang memakan waktu lama tanpa memblokir eksekusi program. Ini sangat penting untuk menjaga aplikasi tetap responsif, terutama saat melakukan operasi input/output (I/O) seperti:
- Mengambil data dari internet (API).
- Membaca atau menulis file dari disk.
- Terhubung ke database.
Pada Dart, hasil dari operasi asinkron direpresentasikan oleh sebuah objek Future
. Sebuah Future
adalah janji bahwa suatu nilai (atau error) akan tersedia di masa depan. Future
memiliki tiga status:
- Uncompleted: Awalnya, operasi belum selesai.
- Completed with a value: Operasi selesai dengan sukses dan mengembalikan nilai.
- Completed with an error: Operasi gagal.
Mendeklarasikan dan Menggunakan Future
Anda dapat menggunakan Future
untuk menyimulasikan operasi yang memakan waktu.
// Ini adalah Future yang akan selesai dalam 2 detik
Future<String> ambilDataDariServer() {
return Future.delayed(Duration(seconds: 2), () {
return 'Data berhasil diambil!';
});
}
Untuk berinteraksi dengan Future
, ada dua cara utama:
1. Menggunakan .then()
, .catchError()
, .whenComplete()
Ini adalah pendekatan lama yang berbasis callback.
.then()
: Akan dieksekusi ketikaFuture
selesai dengan sukses..catchError()
: Akan dieksekusi jika terjadi error..whenComplete()
: Selalu dieksekusi, baik sukses maupun gagal.
ambilDataDariServer().then((data) {
print(data); // Output: Data berhasil diambil!
}).catchError((error) {
print('Terjadi kesalahan: $error');
}).whenComplete(() {
print('Proses pengambilan data selesai.');
});
print('Menunggu data...'); // Ini akan dicetak terlebih dulu
Dalam contoh di atas, “Menunggu data…” dicetak terlebih dahulu karena pemanggilan ambilDataDariServer()
bersifat non-blocking.
2. async
dan await
Cara modern dan lebih disarankan untuk menangani Future
adalah dengan menggunakan kata kunci async
dan await
. Ini membuat kode asinkron terlihat dan terasa seperti kode sinkron yang berurutan.
async
: Digunakan di depan deklarasi fungsi untuk menandakan bahwa fungsi tersebut akan melakukan operasi asinkron dan mengembalikan sebuahFuture
.await
: Digunakan untuk “menunggu” selesainya sebuahFuture
. Kata kunci ini hanya bisa digunakan di dalam fungsi yang ditandai denganasync
.
Contoh penggunaan async
dan await
Future<void> prosesData() async {
print('Memulai proses...');
try {
// Menunggu hingga future selesai, lalu simpan hasilnya di variabel
String data = await ambilDataDariServer();
print(data); // Output: Data berhasil diambil!
} catch (e) {
print('Terjadi kesalahan: $e');
} finally {
print('Proses selesai.');
}
}
void main() {
prosesData();
print('Fungsi prosesData() dipanggil.'); // Ini akan dicetak duluan
}
Meskipun kode di dalam prosesData()
terlihat berurutan, eksekusi main
akan terus berlanjut. prosesData()
akan “berhenti” pada baris await
dan akan melanjutkan eksekusinya setelah ambilDataDariServer()
selesai.
3. async*
dan Stream
Untuk operasi yang menghasilkan serangkaian nilai dari waktu ke waktu (seperti streaming data dari internet atau event dari UI), Dart menggunakan Stream
.
Stream
: Representasi dari serangkaian data asinkron.async*
: Digunakan pada fungsi untuk mengembalikan sebuahStream
. Di dalam fungsiasync*
, Anda bisa menggunakan kata kunciyield
untuk mengirimkan nilai.
Contoh penggunaan Stream
dan async*
Stream<int> hitungMundur(int dari) async* {
for (int i = dari; i >= 0; i--) {
await Future.delayed(Duration(seconds: 1));
yield i; // Mengirimkan nilai i ke stream
}
}
void main() {
final stream = hitungMundur(5);
stream.listen((angka) {
print('Hitungan: $angka');
});
print('Memulai hitungan mundur...');
}
Dalam contoh ini, main
akan terus berjalan. stream.listen()
akan menerima nilai satu per satu saat hitungMundur()
mengirimkannya dengan yield
.
Sample source code bisa di download di github pada link berikut聽dart-tutorial