---
title: 'Eşzamansız Dart'
source: 'https://academia.sh/tr/kurslar/flutter/eszamansiz-dart'
course: Flutter
language: tr
updated: '2026-10-21T05:02:52+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'Gelecek ve akış tiplerini, async ve await sözdizimini bir boyutlanma modeli üzerinde okur'
    - 'Olay döngüsünde senkron kodun, mikro görevlerin ve görev kuyruğunun çalışma sırasını açıklar'
    - 'Genişliği henüz gelmemiş bir bileşenin değer gelmeden önceki ve sonraki boyutlanmasını ölçer'
    - 'Hatalı bir geleceğin try ve catch ile yakalanıp yedek değere dönüştürüldüğünü gösterir'
---

# Eşzamansız Dart

Genişlik sonradan gelen bir bileşenin iki ölçümü. Ders gelecek, async ve await, akış, olay döngüsü ve yalıtılmış işlemci kavramlarını ağacın kurulduğu sıra üzerinden anlatır.

Önceki derste `Banner`'ın 400 isteği hazır bir sayıydı. Gerçek bir ekranda bir bileşenin genişliği çoğu zaman sonradan gelir: bir görselin boyutu okunur, bir dosyanın içeriği çözülür, bir yanıt beklenir. O ana kadar ağaç yine de kurulmak zorundadır. Bu dersin sorusu, değer gelmeden önce ve geldikten sonra aynı bileşenin genişliğini kimin belirlediğidir.

Dart bu duruma **gelecek** (`Future`) tipiyle cevap verir. `Future<int>` şimdi var olmayan, ileride bir `int` ya da bir hata olarak tamamlanacak bir değerdir. `async` ile işaretlenen bir işlev her zaman bir gelecek döndürür; `await` ise bir gelecek tamamlanana kadar o işlevin geri kalanını bekletir, işlevi çağıran taraf bu sırada akışına devam eder.

## Ağaç ve Yardımcı Dosya

Ders boyunca ağaç tek bir yerden kurulur. `buildBody` işlevi genişlik bilinmiyorsa `fill('Avatar')`, biliniyorsa `leaf('Avatar', width)` kullanır. `printAvatar` ağacı 360 genişliğinde ölçer ve yalnız `/Screen/Body/Avatar` satırını yazar. Bu dosya çıktısızdır ve `main` içermez; aşağıdaki bloklar onu içe alır.

```dart
// sizing.dart — bir bilesenin genisligini kimin belirledigini siniflandirir
const sizings = ['dayatilan', 'secilen', 'kirpilan', 'esnetilen'];

class Limit {
  final int min;
  final int? max; // null: sinirsiz
  const Limit(this.min, this.max);

  bool get tight => max == min;
  Limit loosen() => Limit(0, max);
  Limit deflate(int by) => Limit(_floor(min - by), max == null ? null : _floor(max! - by));
  String bounds() => '$min..${max ?? 'sonsuz'}';
}

int _floor(int value) => value < 0 ? 0 : value;

class Part {
  final String kind;
  final String name;
  final int? width; // null: alabildigi kadar genis
  final List<Part> children;
  final int factor;
  final bool tightFlex;
  const Part(this.kind, this.name, this.width, this.children,
      {this.factor = 0, this.tightFlex = true});
}

Part leaf(String name, int width) => Part('leaf', name, width, const []);
Part fill(String name) => Part('leaf', name, null, const []);
Part pad(String name, int padding, Part child) => Part('pad', name, padding, [child]);
Part center(String name, Part child) => Part('center', name, null, [child]);
Part fixed(String name, int width, Part child) => Part('fixed', name, width, [child]);
Part column(String name, List<Part> children) => Part('column', name, null, children);
Part row(String name, List<Part> children) => Part('row', name, null, children);
Part flex(String name, int factor, Part child, {bool tight = true}) =>
    Part('flex', name, null, [child], factor: factor, tightFlex: tight);

class Sizing {
  final String sizing;
  final String path;
  final int width;
  final Limit limit;
  const Sizing(this.sizing, this.path, this.width, this.limit);
}

Sizing classify(String path, int? desire, Limit limit) {
  if (limit.tight) return Sizing('dayatilan', path, limit.min, limit);
  if (desire == null) {
    return limit.max == null
        ? Sizing('kirpilan', path, limit.min, limit)
        : Sizing('esnetilen', path, limit.max!, limit);
  }
  if (desire < limit.min) return Sizing('kirpilan', path, limit.min, limit);
  if (limit.max != null && desire > limit.max!) {
    return Sizing('kirpilan', path, limit.max!, limit);
  }
  return Sizing('secilen', path, desire, limit);
}

int layout(Part part, Limit limit, List<Sizing> log, [String path = '']) {
  final here = '$path/${part.name}';
  final below = <Sizing>[];
  if (part.kind == 'fixed') {
    final own = classify(here, part.width, limit);
    layout(part.children.first, Limit(own.width, own.width), below, here);
    log..add(own)..addAll(below);
    return own.width;
  }
  int? desire;
  switch (part.kind) {
    case 'leaf':
      desire = part.width;
    case 'pad':
      final space = 2 * part.width!;
      desire = layout(part.children.first, limit.deflate(space), below, here) + space;
    case 'center':
      final inner = layout(part.children.first, limit.loosen(), below, here);
      desire = limit.max == null ? inner : null;
    case 'flex':
      desire = layout(part.children.first, limit, below, here);
    case 'column':
      var widest = 0;
      for (final child in part.children) {
        final width = layout(child, limit.loosen(), below, here);
        if (width > widest) widest = width;
      }
      desire = widest;
    case 'row':
      final logs = [for (final _ in part.children) <Sizing>[]];
      final bounded = limit.max != null;
      var used = 0;
      var factors = 0;
      for (var i = 0; i < part.children.length; i++) {
        final child = part.children[i];
        if (child.kind == 'flex' && bounded) {
          factors += child.factor;
        } else {
          used += layout(child, const Limit(0, null), logs[i], here);
        }
      }
      final left = bounded ? _floor(limit.max! - used) : 0;
      var given = 0;
      var seen = 0;
      for (var i = 0; i < part.children.length; i++) {
        final child = part.children[i];
        if (child.kind != 'flex' || !bounded) continue;
        seen += child.factor;
        final share = (seen == factors ? left : left * seen ~/ factors) - given;
        given += share;
        final room = child.tightFlex ? Limit(share, share) : Limit(0, share);
        used += layout(child, room, logs[i], here);
      }
      for (final entries in logs) {
        below.addAll(entries);
      }
      desire = bounded ? null : used;
  }
  final own = classify(here, desire, limit);
  log..add(own)..addAll(below);
  return own.width;
}

List<Sizing> measure(Part root, int screen) {
  final log = <Sizing>[];
  layout(root, Limit(screen, screen), log);
  return log;
}

void printSizes(List<Sizing> log) {
  for (final entry in log) {
    print('${entry.sizing}: ${entry.path} genislik=${entry.width} kisit=${entry.limit.bounds()}');
  }
}

void countSizings(List<Sizing> log) {
  for (final name in sizings) {
    print('$name: ${log.where((entry) => entry.sizing == name).length}');
  }
  print('ebeveyn: ${log.where((entry) => entry.sizing != 'secilen').length}');
}
```

```dart
// avatar_body.dart — avatar genisligine gore sutun agaci kurar ve avatari olcer
import 'sizing.dart';

Part buildBody(int? width) {
  final avatar = width == null ? fill('Avatar') : leaf('Avatar', width);
  return pad('Screen', 16, column('Body', [leaf('Name', 120), avatar]));
}

void printAvatar(int? width) {
  final log = measure(buildBody(width), 360);
  printSizes(log.where((entry) => entry.path == '/Screen/Body/Avatar').toList());
}
```

`int? width` parametresi ilk dersteki fikri taşır: `null`, genişliğin henüz bilinmediğini söyler. `width == null ? fill('Avatar') : leaf('Avatar', width)` bir **koşul ifadesidir**; `width` `null` değilse ikinci kolda `int` olarak kullanılabilir, çünkü derleyici `null` denetimini izler.

**DB1.** Modelde bekleme süresi yoktur, yalnız sıra vardır. `loadWidth` hemen tamamlanır; ölçülen şey, değerin geldiği anın öncesi ve sonrasındaki iki ağaçtır. Model çerçevenin kendisi değildir.

## Gelecek ve await

Aşağıdaki blok bir gelecek kurar, çağıran tarafın akışına devam ettiğini gösterir ve değeri `await` ile alır. Her adım bir satır basar.

```dart
// main.dart
import 'sizing.dart';
import 'avatar_body.dart';

Future<int> loadWidth() async {
  print('yukleme basladi');
  return 200;
}

Future<void> main() async {
  print('istek gonderildi');
  final pending = loadWidth();
  print('beklemeden devam');
  final width = await pending;
  print('deger geldi: $width');
  printAvatar(width);
}
```

```text
istek gonderildi
yukleme basladi
beklemeden devam
deger geldi: 200
secilen: /Screen/Body/Avatar genislik=200 kisit=0..328
```

`loadWidth` çağrıldığında gövdesi ilk `await`'e ya da sona kadar hemen çalışır; bu yüzden `yukleme basladi` satırı `beklemeden devam`'dan önce gelir. `loadWidth`'ın döndürdüğü gelecek `pending` değişkenine girer. `await pending` ifadesine gelindiğinde `main` durur ve değer gelince kaldığı yerden sürer. Değer gelmiştir, `Avatar` 200 ister ve aralığın içinde kaldığı için seçilendir.

## Olay Döngüsü

Dart kodu tek bir iş parçacığında, bir **olay döngüsü** ile çalışır. Çalışan kod sonuna kadar sürer. Sonra döngü iki kuyruğa bakar: önce **mikro görev kuyruğunu** boşaltır, ardından **görev kuyruğundan** bir görev alır. Bir `await` ya da bir `Future(...)` çağrısı, devamını bu kuyruklardan birine bırakır. Aşağıdaki blok sırayı numaralarla gösterir.

```dart
// main.dart
import 'sizing.dart';
import 'dart:async';
import 'avatar_body.dart';

void main() {
  print('1 senkron: ilk kurulus');
  printAvatar(null);
  scheduleMicrotask(() {
    print('3 mikro gorev');
    printAvatar(200);
  });
  Future(() {
    print('4 gorev kuyrugu');
    printAvatar(320);
  });
  print('2 senkron: main sonu');
}
```

```text
1 senkron: ilk kurulus
esnetilen: /Screen/Body/Avatar genislik=328 kisit=0..328
2 senkron: main sonu
3 mikro gorev
secilen: /Screen/Body/Avatar genislik=200 kisit=0..328
4 gorev kuyrugu
secilen: /Screen/Body/Avatar genislik=320 kisit=0..328
```

Numaralar kodun yazılış sırasına değil, çalışma sırasına aittir. `main` bitmeden hiçbir kuyruk işlenmez; bu yüzden 2 numaralı satır 3'ten önce basılır. İlk ölçümde değer yoktur ve `Avatar` esnetilendir. Mikro görev değeri 200 yapar, görev kuyruğundaki iş 320 yapar; ikisinde de istek aralığın içindedir ve `Avatar` seçilendir.

## Hata ve Akış

Bir gelecek bir değerle değil, bir hatayla da tamamlanabilir. `await` o hatayı çağıran tarafa fırlatır ve `try`/`catch` onu yakalar. Aşağıdaki blokta yükleme başarısız olur, işlev yedek bir genişliğe döner ve ağaç bu genişlikle kurulur. Hata yakalandığı için programa yayılmaz; çıktıda yedek genişliği bildiren tek satırın ardından ağacın ölçümü yazılır.

```dart
// main.dart
import 'sizing.dart';
import 'avatar_body.dart';

Future<int> loadWidth() async {
  throw StateError('baglanti yok');
}

Future<int> loadWidthOrFallback() async {
  try {
    return await loadWidth();
  } catch (_) {
    print('yukleme basarisiz, 96 kullanilir');
    return 96;
  }
}

Future<void> main() async {
  final width = await loadWidthOrFallback();
  printAvatar(width);
}
```

```text
yukleme basarisiz, 96 kullanilir
secilen: /Screen/Body/Avatar genislik=96 kisit=0..328
```

Gelecek tek bir değer taşır. Zamana yayılmış birden çok değer için Dart **akış** (`Stream`) tipini kullanır. `async*` ile işaretlenen bir işlev `yield` ile değerleri sırayla üretir; `await for` döngüsü her değeri geldiği sırayla alır.

```dart
// main.dart
import 'sizing.dart';
import 'avatar_body.dart';

Stream<int> widths() async* {
  yield 200;
  yield 320;
  yield 400;
}

Future<void> main() async {
  await for (final width in widths()) {
    print('akis degeri: $width');
    printAvatar(width);
  }
}
```

```text
akis degeri: 200
secilen: /Screen/Body/Avatar genislik=200 kisit=0..328
akis degeri: 320
secilen: /Screen/Body/Avatar genislik=320 kisit=0..328
akis degeri: 400
kirpilan: /Screen/Body/Avatar genislik=328 kisit=0..328
```

Her yeni değer ağacın yeniden ölçülmesini getirir. İlk iki değer `0..328` aralığında kalır ve seçilendir; üçüncüsü 400 olduğundan kısıt tarafından kırpılır. Aynı bileşende, aynı yerde, değer akarken boyutlanma sahibi değişir.

**DB2.** Akış modelde üç sabit değerden oluşur. Gerçek bir akış değerlerini zamana yayar; model yalnız sırayı korur ve değerler arasındaki bekleme yoktur.

## Yalıtılmış İşlemci

Olay döngüsü işi bölüştürür ama paralel çalıştırmaz: ağır bir hesap döngüyü tutarsa kuyruklar işlenemez ve arayüz donar. Dart bunun için **yalıtılmış işlemci** (isolate) sunar. Yalıtılmış işlemci kendi belleği ve kendi olay döngüsü olan ayrı bir yürütme birimidir; ana birimle bellek paylaşmaz, yalnız ileti alışverişi yapar. Aşağıdaki parça ağır bir çözümlemeyi ayrı bir birime taşır. Parça ölçülmez; model yalıtılmış işlemciyi kurmaz.

```dart
// Platform kodu: yalitilmis islemci
import 'dart:isolate';

Future<int> parseInBackground(String raw) {
  return Isolate.run(() => int.parse(raw));
}
```

Dönüş tipi yine bir `Future<int>`'tir. Çağıran taraf için fark yoktur: değer sonradan gelir ve ağaç, yukarıdaki iki ölçümde olduğu gibi, değer gelmeden ve geldikten sonra kurulur. Ağacın kuruluşu ana birimde kalır; yalıtılmış işlemci yalnız genişliği hesaplayan işi taşır.

## Sınırlayıcı Ölçüm

Aşağıdaki blok bir bileşenin genişliği gelmeden önce ve geldikten sonra ağacın tamamını ölçer ve her ölçümün sayımını verir. Odak, ikinci ölçümdeki `/Screen/Body/Avatar`'dır.

```dart
// main.dart
import 'sizing.dart';
import 'avatar_body.dart';

Future<int> loadWidth() async => 200;

Future<void> main() async {
  print('olcum 1: deger gelmeden once');
  final before = measure(buildBody(null), 360);
  printSizes(before);
  countSizings(before);

  final width = await loadWidth();
  print('olcum 2: deger geldikten sonra');
  final after = measure(buildBody(width), 360);
  printSizes(after);
  countSizings(after);
}
```

```text
olcum 1: deger gelmeden once
dayatilan: /Screen genislik=360 kisit=360..360
dayatilan: /Screen/Body genislik=328 kisit=328..328
secilen: /Screen/Body/Name genislik=120 kisit=0..328
esnetilen: /Screen/Body/Avatar genislik=328 kisit=0..328
dayatilan: 2
secilen: 1
kirpilan: 0
esnetilen: 1
ebeveyn: 3
olcum 2: deger geldikten sonra
dayatilan: /Screen genislik=360 kisit=360..360
dayatilan: /Screen/Body genislik=328 kisit=328..328
secilen: /Screen/Body/Name genislik=120 kisit=0..328
secilen: /Screen/Body/Avatar genislik=200 kisit=0..328
dayatilan: 2
secilen: 2
kirpilan: 0
esnetilen: 0
ebeveyn: 2
```

**Bu dersin boyutlanması: seçilen.** Değer gelmeden `Avatar` istek bildirmez, sütun kısıtı `0..328` olduğundan alabildiği kadar genişler ve esnetilen olur. Değer gelince `Avatar` 200 ister, 200 aralığın içindedir ve genişliği `Avatar` seçer. İki ölçüm arasında ağaçta yalnız `Avatar`'ın isteği değişmiştir ve boyutlanma bu tek düğümde el değiştirir. Sayım bunu özetler: ebeveyn 3'ten 2'ye iner.

## Özet

- Bu dersin boyutlanması: seçilen. Değer gelmeden `/Screen/Body/Avatar` esnetilendir; 200 gelince isteği `0..328` aralığında kalır ve genişliği `Avatar` seçer.
- `Future<int>` ileride tamamlanacak bir değerdir. `async` işlev gelecek döndürür, `await` değer gelene kadar işlevi bekletir ve çağıran taraf bu sırada devam eder.
- Olay döngüsü senkron kodu bitirir, mikro görev kuyruğunu boşaltır, sonra görev kuyruğundan bir görev alır. Çıktıdaki numaralar bu sırayı gösterir.
- Başarısız bir gelecek `try`/`catch` ile yakalanıp yedek değere çevrilir. Akış zamana yayılmış değerler taşır ve her değer ağacı yeniden ölçtürür.
- Yalıtılmış işlemci ağır işi ayrı bir bellekte yürütür ve sonucu yine bir gelecek olarak döndürür.

## Sonraki Adım

Ağaç şimdiye kadar `leaf`, `pad` ve `column` çağrılarının bileşimiydi. **Bileşen Kavramı** dersi bu çağrıları çerçevenin bileşen kavramına bağlar: bir bileşenin ne olduğunu, ağaçta nasıl iç içe girdiğini ve bir kartın başka bir kısıtta neden başka bir sahiple karşılaştığını ölçer.
