Back to list
AVRA-CADAVRA

async-await-patterns

by AVRA-CADAVRA

0🍴 0📅 Jan 24, 2026

SKILL.md


name: async-await-patterns description: Enforces async/await patterns over .then() chains, proper error handling, mounted checks. Use when writing async code, handling Futures, or working with async operations.

Async/Await Patterns

Core Rule

✅ ALWAYS use async/await instead of .then() chains ✅ ALWAYS handle errors in async operations (try-catch) ✅ Check mounted before setState() in async callbacks (Flutter widgets)

Basic Pattern

// ✅ GOOD
Future<void> loadData() async {
  try {
    final data = await repository.fetch();
    if (mounted) {
      setState(() => _data = data);
    }
  } catch (e, st) {
    developer.log('Failed to load data', error: e, stackTrace: st);
  }
}

// ❌ BAD
void loadData() {
  repository.fetch().then((data) {
    setState(() => _data = data); // Missing mounted check
  }).catchError((e) {
    // Silent failure
  });
}

Error Handling

Always wrap async operations in try-catch:

Future<Result<User>> getUser(String id) async {
  try {
    final user = await repository.getUser(id);
    return Success(user);
  } on NetworkException catch (e) {
    return Failure('Network error: ${e.message}');
  } catch (e, st) {
    developer.log('Unexpected error', error: e, stackTrace: st, name: 'UserService');
    return Failure('Failed to load user');
  }
}

Widget Mounted Checks

Always check mounted before setState() in async callbacks:

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    loadData();
  }
  
  Future<void> loadData() async {
    try {
      final data = await repository.fetch();
      if (mounted) { // ✅ Check mounted
        setState(() {
          _data = data;
        });
      }
    } catch (e, st) {
      if (mounted) { // ✅ Check mounted
        setState(() {
          _error = e.toString();
        });
      }
    }
  }
}

Multiple Async Operations

// ✅ GOOD: Sequential with error handling
Future<void> loadAllData() async {
  try {
    final user = await loadUser();
    final settings = await loadSettings();
    final preferences = await loadPreferences();
    
    if (mounted) {
      setState(() {
        _user = user;
        _settings = settings;
        _preferences = preferences;
      });
    }
  } catch (e, st) {
    developer.log('Failed to load data', error: e, stackTrace: st);
  }
}

// ✅ GOOD: Parallel with error handling
Future<void> loadAllDataParallel() async {
  try {
    final results = await Future.wait([
      loadUser(),
      loadSettings(),
      loadPreferences(),
    ]);
    
    if (mounted) {
      setState(() {
        _user = results[0];
        _settings = results[1];
        _preferences = results[2];
      });
    }
  } catch (e, st) {
    developer.log('Failed to load data', error: e, stackTrace: st);
  }
}

FutureOr Pattern

When method can be sync or async:

FutureOr<String> getData() {
  if (_cache != null) {
    return _cache!; // Sync return
  }
  return fetchFromServer(); // Async return
}

Completer Pattern (Rare)

Only use Completer when necessary (prefer async/await):

Future<String> convertCallback() {
  final completer = Completer<String>();
  
  someCallbackApi((result) {
    completer.complete(result);
  });
  
  return completer.future;
}

Anti-Patterns

❌ .then() Chains:

repository.fetch()
  .then((data) => processData(data))
  .then((processed) => saveData(processed))
  .catchError((e) => handleError(e)); // BAD

❌ Missing Error Handling:

Future<void> loadData() async {
  final data = await repository.fetch(); // No try-catch - BAD
  setState(() => _data = data);
}

❌ Missing Mounted Check:

Future<void> loadData() async {
  final data = await repository.fetch();
  setState(() => _data = data); // No mounted check - BAD
}

❌ Future.value(null).then():

Future.value(null).then((_) => doSomething()); // Use await instead

Best Practices

  1. Always use async/await for async operations
  2. Always wrap async operations in try-catch
  3. Always check mounted before setState() in widgets
  4. Use FutureOr<T> when method can be sync or async
  5. Prefer async/await over Completer when possible
  6. Use Future.wait() for parallel operations
  7. Never use .then() chains in new code

Score

Total Score

60/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新がある

0/10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

0/5

Reviews

💬

Reviews coming soon