dartasyncstreamMahir3 mnt baca

Await For Mendalam

Mengonsumsi stream dengan await for: break, error, dan pola real-time.

Loop yang sabar menunggu

await for adalah cara paling bersih mengonsumsi stream: ia menunggu tiap nilai tiba, memprosesnya, lalu menunggu lagi, sampai stream selesai. Dibanding .listen() dengan callback, alurnya sekuensial dan mudah diikuti.

Analogi: await for itu seperti penjaga pintu yang memeriksa tiap tamu yang datang satu per satu. .listen() itu seperti memasang bel: tiap ada tamu, bel berbunyi dan kamu lari ke pintu.

Kenapa await for ada?

Karena callback .listen() memecah logika menjadi potongan (onData, onError, onDone) yang sulit dirangkai untuk alur kompleks. await for menyatukannya dalam satu badan loop dengan try-catch-finally biasa.

Bentuk dasar dan kontrol alur

dart
Stream<int> angka() async* {
  for (int i = 1; i <= 10; i++) {
    await Future.delayed(Duration(milliseconds: 100));
    yield i;
  }
}

Future<void> main() async {
  await for (var n in angka()) {
    print('Dapat: $n');
    if (n == 3) {
      print('Cukup, berhenti!');
      break; // keluar loop, stream dibatalkan otomatis
    }
  }
  print('Loop selesai.');
}

break di dalam await for otomatis membatalkan langganan stream. continue melewati nilai saat ini. Semua kontrol alur loop biasa berlaku.

Contoh kedua, akumulasi real-time:

dart
Stream<double> sensorSuhu() async* {
  var data = [36.5, 36.7, 37.8, 36.6, 38.2, 36.4];
  for (var s in data) {
    await Future.delayed(Duration(milliseconds: 200));
    yield s;
  }
}

Future<void> main() async {
  int hitung = 0;
  double total = 0;
  double maks = 0;

  await for (var suhu in sensorSuhu()) {
    hitung++;
    total += suhu;
    if (suhu > maks) maks = suhu;

    if (suhu > 37.5) {
      print('PERINGATAN: demam terdeteksi ($suhu°C)');
    }
  }

  print('Rata-rata: ${(total / hitung).toStringAsFixed(1)}°C');
  print('Maksimum: $maks°C');
}

Pola klasik stream processing: agregasi berjalan (running aggregate) + deteksi kondisi, semua dalam satu loop yang terbaca.

Error handling di await for

dart
Stream<int> kadangRusak() async* {
  yield 1;
  yield 2;
  throw Exception('sensor mati!');
}

Future<void> main() async {
  try {
    await for (var n in kadangRusak()) {
      print('Proses: $n');
    }
  } catch (e) {
    print('Stream error, tapi nilai 1 dan 2 sudah diproses: $e');
  } finally {
    print('Bersih-bersih resource.');
  }
}

try-catch-finally biasa bekerja mengelilingi await for. Error stream ditangkap seperti error biasa. Nilai yang sudah diproses tidak hilang.

await for vs listen: kapan pakai apa

dart
Future<void> denganAwaitFor() async {
  // Cocok: alur sekuensial, butuh break/return
  await for (var n in Stream.fromIterable([1, 2, 3])) {
    if (n == 2) return; // bisa return dari fungsi!
    print(n);
  }
}

void denganListen() {
  // Cocok: fire-and-forget, banyak pendengar independen
  var sub = Stream.fromIterable([1, 2, 3]).listen(
    (n) => print(n),
    onDone: () => print('selesai'),
  );
  // sub.cancel(); // bisa dibatalkan manual
}
await forlisten
GayaSekuensial, blocking loopCallback, non-blocking
break/returnBisaTidak (pakai cancel)
Banyak pendengarTidak (satu loop)Bisa (broadcast)
Cocok untukPipeline pemrosesanEvent handler UI

Kesalahan umum

1. await for di fungsi sync

dart
// SALAH
// void main() {
//   await for (var x in stream) {}
// }

Fungsi harus async (mengembalikan Future).

2. Dua await for pada single-subscription stream

Sama seperti listen ganda: stream single-subscription hanya bisa dikonsumsi sekali. Butuh dua konsumen? Broadcast atau buat stream baru.

3. Lupa bahwa break membatalkan stream

Ini biasanya yang diinginkan, tapi pahami konsekuensinya: generator berhenti, resource dibersihkan. Jika butuh "jeda lalu lanjut", jangan break; pakai flag dan continue.

Kesimpulan

await for = konsumsi stream gaya sekuensial dengan kontrol alur penuh (break/continue/return) dan try-catch biasa. Pilih await for untuk pipeline pemrosesan, .listen() untuk event handler.

Catatan teknis: await for pada broadcast stream melewatkan nilai yang tiba sebelum loop mulai (tidak ada buffer replay). Untuk "nilai terakhir selalu tersedia", pertimbangkan BehaviorSubject dari rxdart.

Tantangan

Monitor suhu

Buat Stream<double> suhuAcak() async* yang yield 10 suhu acak 35.0-39.0. Konsumsi dengan await for: hitung rata-rata, dan break dengan peringatan jika ada suhu > 38.5.

text
import 'dart:math';

Stream<double> suhuAcak() async* {
  var r = Random();
  // TODO: yield 10 suhu 35.0 + r.nextDouble() * 4
}

Future<void> main() async {
  // TODO: await for, rata-rata, break jika > 38.5
}

Kuis Bab

Uji pemahamanmu: Bab 5: Null Safety & Async

Jawab 5 soal berikut, lalu tekan "Periksa Jawaban".

1.Apa arti deklarasi String? nama; di Dart?

2.Apa nilai y setelah: var x; var y = x ?? 'default';

3.Kapan LateInitializationError terjadi?

4.Fungsi yang ditandai async selalu mengembalikan apa?

5.Apa perbedaan utama Future dan Stream?