---
title: کپسول‌های ناهمزمان
description: با اصول اولیه کپسول‌های ناهمزمان در ReArch آشنا شوید.
---

# کپسول‌های ناهمزمان
خیلی وقت‌ها می‌خوای یه کپسول بسازی که دور یه کد ناهمزمان (asynchronous) بپیچه  
تا بتونی از اون کد ناهمزمان توی کپسول‌های دیگه استفاده کنی.  
این یه مشکل جالب ایجاد می‌کنه، چون هر کپسولی به‌صورت ذاتی همزمانی (synchronous) هست.  
راه‌حل: اثرات جانبی!  
اثرات جانبی در واقع مکانیزمی هستن که به رویدادهای خارجی اجازه می‌دن آپدیت‌های کپسول رو فعال کنن،  
و این دقیقاً چیزیه که اینجا نیاز داریم.

## یه مثال
<CodeGroup title="ایجاد کپسول‌های ناهمزمان">
  ```dart
  int countCapsule(CapsuleHandle _) => 0;

  /// کپسول "خام" ناهمزمان ما که مستقیماً یه Future برمی‌گردونه (می‌تونه Stream هم برگردونه).  
  Future<int> delayedAsyncCapsule(CapsuleHandle use) async {
    // همه خوندن‌های کپسول و اثرات جانبی *باید* قبل از اولین `await` باشن.  
    // (ولی اغلب بهتره توی کپسول‌های ناهمزمان از اثرات جانبی استفاده نکنی.)  
    final count = use(countCapsule);

    final delayedCount = await Future.delayed(
      const Duration(seconds: 1),
      () => count,
    );

    return delayedCount + 1;
  }

  /// کپسول "wrapper" ما که یه AsyncValue برمی‌گردونه، و اغلب توی کد UI مفیدتره.  
  /// این wrapper همچنین مطمئن می‌شه که مقدار delayedAsyncCapsule توی کانتینر کش می‌شه،  
  /// چون این کپسول از یه اثر جانبی استفاده می‌کنه.  
  /// توجه کن که می‌تونی مستقیماً از `use.future` توی کد UI هم استفاده کنی،  
  /// اگه نمی‌خوای Future رو به‌صورت مشتاقانه (eagerly) کش کنی.  
  AsyncValue<int> delayedCapsule(CapsuleHandle use) {
    final delayed = use(delayedAsyncCapsule);
    return use.future(delayed);
  }
  ```

  ```rust
  // چند راه مختلف برای این کار وجود داره، ولی روش زیر استانداردترینه.  
  // TODO: مثال از rearch-tokio کپی بشه  
  ```
</CodeGroup>

## کپسول‌های ناهمزمان قابل‌تازه‌سازی
<Info>این بخش فقط برای Dart/Flutter هست، چون Futureها توی Rust یه مقدار متفاوت مدیریت می‌شن.</Info>

کپسول `delayedCapsule` که توی مثال بالا ساختیم، فقط یه دید "فقط-خوندن" از Future هست.  
این کپسول هیچ حالت خودش رو نداره و فقط مقدار فعلی کپسول ناهمزمان رو ذخیره می‌کنه.  
اگه بخوای حالت delayedCapsule رو تازه‌سازی (refresh) کنی، مثلاً با گرفتن داده جدید از آنلاین،  
نیاز به یه رویکرد کمی متفاوت داریم که یه Future جدید رو جایگزین کنه.  
اثر جانبی `refreshableFuture` به کمکمون میاد!

```dart
(AsyncValue<int>, void Function()) refreshableDelayedCapsule(CapsuleHandle use) {
  return use.refreshableFuture(() {
    return Future.delayed(const Duration(seconds: 1), () => 1234);
  });
}
```

یه معادل هم برای فقط باطل کردن (invalidation) وجود داره: `invalidatableFuture`.  
فرقش اینه که `invalidatableFuture` فقط وقتی یه Future جدید اجرا می‌کنه که در حال حاضر استفاده بشه،  
در حالی که `refreshableFuture` همیشه که تازه‌سازی بشه یه Future جدید اجرا می‌کنه.

## `AsyncValue`/`AsyncState` چیه؟
ممکنه متوجه بشی که وقتی اثرات جانبی ناهمزمان رو اعمال می‌کنی،  
داده‌هایی از نوع `AsyncValue<T>` یا `AsyncState<T>` بهت داده می‌شه.

این کاملاً عمدیه؛  
این بهت اجازه می‌ده حالت فعلی کد ناهمزمان رو به‌صورت همزمانی مدیریت کنی،  
که لازمه چون ساخت‌های ReArch *کاملاً همزمانی* هستن و (توی دارت) *نمی‌تونن خطا پرتاب کنن*.  
برای همین، خیلی توصیه می‌شه که یاد بگیری چطور با `AsyncValue`/`AsyncState` کار کنی  
به‌جای اینکه سعی کنی ازشون دوری کنی.

### `AsyncValue` توی دارت
`AsyncValue`ها سه حالت رو برای Futureها و Streamها نشون می‌دن:  
- Future/Stream هنوز در حال لود شدن و چیزی منتشر نکرده (`AsyncLoading`)  
- Future/Stream داده منتشر کرده (`AsyncData`)  
- Future/Stream یه خطا منتشر کرده (`AsyncError`)  

برای اطلاعات بیشتر، مستندات API مربوط به `AsyncValue` رو ببین.

### `AsyncState` توی Rust
`AsyncState`ها دو حالت رو برای Futureها نشون می‌دن:  
- Future هنوز در حال لود شدن و چیزی منتشر نکرده (`Loading`)  
- Future داده منتشر کرده (`Complete`)  

برای اطلاعات بیشتر، مستندات API مربوط به `AsyncState` رو ببین.
