Future və async/await
Future<T> — gələcəkdə gələcək bir dəyəri (və ya xətanı) təmsil edən obyektdir. Üç vəziyyəti var: uncompleted → completed with value və ya completed with error. Bir dəfə tamamlandıqdan sonra vəziyyət dəyişmir.
Əsas qaydalar:
asyncfunksiya həmişəFutureqaytarır.Future<int> f() async => 42;yazsan da,intyox,Future<int>alırsan. Heç nə qaytarmırsaFuture<void>.awaitfuture tamamlanana qədər həmin funksiyanı dayandırır, bütün proqramı yox — event loop işləməyə davam edir.asyncfunksiyanın içindən atılan istisna sinxron atılmır: o, qaytarılan future-u error ilə tamamlayır. Ona görəf()çağırışının özütry-a düşməz —await f()düşər.- Await edilməyən ("floating") future yenə də işləyir; sadəcə sən nəticəni və xətanı görmürsən. Bu, ən çox rast gəlinən async bug-dur.
| Konstruksiya | Nə edir | Nə vaxt istifadə et |
|---|---|---|
| `Future.value(x)` | Dərhal dəyərlə tamamlanmış future | Test-də fake, cache hit, sinxron nəticəni async API-yə uyğunlaşdırmaq |
| `Future.error(e)` | Xəta ilə tamamlanmış future | Xəta yolunu test etmək |
| `Future.delayed(d, fn)` | `d` müddətindən sonra `fn`-i event queue-da işə salır | Retry backoff, simulyasiya; **testdə `FakeAsync` ilə əvəzlə** |
| `Future.wait([...])` | Hamısını paralel gözləyir, `List` qaytarır | Bir-birindən asılı olmayan çağırışlar |
| `Future.any([...])` | İlk tamamlananın nəticəsi | Timeout pattern-i, yarışan mənbələr |
| `future.timeout(d)` | `d` keçsə `TimeoutException` atır | Şəbəkə çağırışlarına həmişə tətbiq et |
Ardıcıl, yoxsa paralel? Bu, kod review-da ən çox rast gəlinən performans qüsurudur.
final a = await getUser(); final b = await getOrders();— asılılıq yoxdursa, bu, vaxtları toplayır.final [a, b] = await Future.wait([getUser(), getOrders()]);— hər ikisi eyni anda başlayır, ümumi vaxt ən yavaşı qədərdir.
Diqqət: Future.wait fail-fast-dır — biri error verən kimi ümumi future error ilə tamamlanır, amma qalanları dayanmır, arxa planda işləməyə davam edir. Onların da xətası varsa, o xətalar tutulmamış qalır. Hər nəticəni ayrıca görmək lazımdırsa eagerError yerinə hər future-a fərdi catchError qoy və ya nəticələri Result tipinə bük.
`then`/`catchError`, yoxsa `await`? Semantika eynidir, amma await üstündür: stack trace oxunaqlı olur, try/catch/finally işləyir, şərt və dövrələr təbii yazılır. then yalnız o halda qalır ki, funksiyanı async etmək istəmirsən (məsələn future-u sadəcə transformasiya edib qaytarırsan).
Async gap — mövzunun ən vacib anlayışı. await yazdığın hər yerdə funksiyan dayanır və nəzarət event loop-a qayıdır. Həmin "boşluq"da başqa hər şey baş verə bilər: istifadəçi ekranı bağlayır, obyekt dispose olunur, eyni funksiya ikinci dəfə çağırılır, cache təmizlənir.
Bundan iki praktik qayda çıxır:
- `await`-dan sonra oxuduğun state-i yenidən yoxla.
await-dan əvvəl doğru olan şərt sonra doğru olmaya bilər. Flutter-də bunun adıif (!mounted) return;-dir və analyzer-inuse_build_context_synchronouslyxəbərdarlığı məhz bu problem haqqındadır. - Eyni əməliyyatın təkrar başlamasını idarə et. İki
refresh()eyni anda işləyirsə, hansının nəticəsinin sonda yazılacağı zəmanətsizdir. Ya əvvəlkini ləğv et, ya da nəticəni bir "request id" ilə yoxla.
Async gap həm də timing-dən asılı bug-ların əsas mənbəyidir: onlar lokal maşında görünmür, çünki orada şəbəkə sürətlidir və boşluq qısadır.
Müsahibə ipucu. Üç sual demək olar zəmanətlidir.
"`async` funksiya nə qaytarır?" — cavab "həmişə Future", və dərhal nəticəni əlavə et: buna görə async funksiyanın içindən atılan istisna sinxron atılmır, future-u error ilə tamamlayır.
"Bu iki `await`-i necə sürətləndirərdin?" — Future.wait de, sonra mütləq şərti əlavə et: yalnız aralarında asılılıq yoxdursa. Bu şərti deməyən namizəd yarımçıq cavab vermiş olur.
"Async gap nədir?" — await-dan sonra dünyanın dəyişmiş ola biləcəyini izah et və konkret nümunə ver: await-dan sonra _disposed (Flutter-də mounted) yoxlanışı. Ən çox edilən səhv: await-in "proqramı dayandırdığını" demək. Dayanan yalnız həmin funksiyadır — event loop işləməyə davam edir.
📚 Mənbələr və sənədlər
- Asinxron proqramlaşdırmarəsmidart.dev
- Future classrəsmiapi.dart.dev