Sparround

Asinxron kodda xəta emalı

async funksiyada try/catch/finally sinxron kodda olduğu kimi işləyir — bir şərtlə: xəta await edilmiş çağırışdan gəlməlidir.

try { await repo.refresh(); } catch (e) { ... }

Burada await iki iş görür: nəticəni gözləyir və Future-un xətasını cari frame-ə bağlayır — yəni həmin xəta bu try blokunun içindən atılmış kimi davranır.

await yazmasan, funksiya Future-u yaradıb dərhal irəli gedir; try bloku bitir, sonra Future fail olur — və artıq onu tutacaq heç bir catch qalmır. Bu, "floating future" adlanır və Dart interview-larının ən sevimli sualıdır.

finally uğur, xəta və rethrow hallarının hamısında icra olunur — resurs bağlamaq (StreamSubscription.cancel(), client.close()) üçün doğru yer məhz odur.

MexanizmNəyi tuturNə vaxt istifadə edilir
`try/await/catch`Sinxron `throw`-ları və `await` edilmiş Future-un xətasınıDefault seçim — kodun 90%-i belə yazılır
`on FormatException catch (e, st)`Yalnız həmin tipdəki xətanı, stack trace ilə birlikdəFərqli xəta tiplərinə fərqli reaksiya lazım olanda
`future.catchError(...)`Həmin Future zəncirindəki xətanı; `test:` parametri ilə filtr edilə bilər`await` mümkün olmayan yerlərdə (məs. `unawaited(...)` ilə fire-and-forget)
`future.then(onValue, onError: ...)`Yalnız ƏVVƏLKİ mərhələnin xətasını — `onValue` içində atılan xətanı tutmurİki halı ayırmaq lazım olanda; incə fərqinə görə interview-da tez-tez soruşulur
`stream.listen(onError: ..., cancelOnError: ...)`Həmin subscription-a çatan xətaları (default olaraq subscription davam edir)Listener tərəfində — UI-a xəta göstərmək, log yazmaq
`stream.handleError(..., test: ...)`Pipeline-dan keçən xətaları — onları udur və ya çevirirStream-i emal edən zəncirin ortasında, listener-i təmiz saxlamaq üçün
`runZonedGuarded(body, onError)`Zone daxilində heç kimin tutmadığı bütün async xətalarıSon müdafiə xətti — crash reporting (Sentry, Crashlytics)

`Error` və `Exception` fərqi Dart-da konvensiyadır, dil qaydası deyil — hər ikisini throw etmək olar, hər ikisi catch (e) ilə tutulur. Fərq niyyətdədir:

  • `Exception`gözlənilən, bərpa oluna bilən vəziyyət: şəbəkə düşdü, JSON pozuqdur, kart rədd edildi. Sən bunları atırsan və çağıran tərəf tutur.
  • `Error`proqramçı səhvi: ArgumentError, StateError, RangeError, LateInitializationError, TypeError. Bunlar tutulmaq üçün deyil, düzəldilmək üçündür. Kitabxana yazırsansa, kontraktı pozan çağırışa ArgumentError atmaq düzgündür; onu catch etmək isə demək olar ki, həmişə səhvdir.

Öz exception sinifin: class PaymentDeclined implements Exceptionextends yox, implements (Exception sadəcə interfeysdir). Həmişə toString() override et, əks halda log-da faydasız Instance of 'PaymentDeclined' görürsən. Sahələr əlavə et (code, retryable) — çağıran tərəf mətn parse etməməlidir.

`rethrow` və stack trace: catch (e) { throw e; } stack trace-i sıfırlayır və xətanın əsl mənbəyini itirirsən. rethrow orijinal trace-i saxlayır. Xətanı başqa tipə "bükürsənsə", trace-i əl ilə ötür: Error.throwWithStackTrace(CheckoutFailure(e), st).

Interview tövsiyəsi: sənə çox güman ki, await-siz çağırışı olan bir kod parçası göstərib "niyə catch işləmir?" soruşacaqlar. Cavabı mexanizmlə ver, hafizədən deyil: "await Future-un xətasını cari frame-ə bağlayır; await yoxdursa, try bloku Future fail olmamışdan əvvəl bitir, ona görə xəta zone-a qalxır və unhandled olur." Sonra üç həll təklif et: await əlavə et, niyyət fire-and-forget-dirsə unawaited(... .catchError(...)) yaz, və ya Future.wait ilə hamısını topla. Bu bir cavabla həm dil modelini, həm də praktikanı göstərirsən.

📚 Mənbələr və sənədlər