Sobes.tech
Middle

Czym są generatory w Dart (sync* i async*) i jak działają?

sobes.tech AI

Odpowiedź od AI

Generatory w Dartzie to funkcje, które zwracają sekwencję wartości w miarę ich generowania, a nie cały wynik od razu. Używa się słów kluczowych sync* dla generatorów synchronicznych i async* dla asynchronicznych.

Generator synchroniczny (sync*)

Zwracają obiekt typu Iterable. Używają słowa kluczowego yield do emitowania kolejnej wartości. Strumień wykonania jest wstrzymywany do momentu, gdy zostanie poproszona o następną wartość (np. w pętli for-in).

Iterable<int> countUpTo(int max) sync* {
  for (int i = 1; i <= max; i++) {
    yield i; // Emitowanie wartości
  }
}

Generator asynchroniczny (async*)

Zwracają obiekt typu Stream. Używają słowa kluczowego yield do emitowania kolejnej wartości. Używają także yield*, aby emitować wszystkie wartości z innego Stream. Strumień wykonania jest wstrzymywany i wznawiany, gdy pojawi się nowe zdarzenie asynchroniczne.

Stream<int> countUpToAsync(int max) async* {
  for (int i = 1; i <= max; i++) {
    await Future.delayed(Duration(milliseconds: 100)); // Symulacja pracy asynchronicznej
    yield i; // Emitowanie wartości
  }
}

Jak działają:

Po wywołaniu funkcji generatora, ciało funkcji nie jest od razu wykonywane. Zwracany jest obiekt (zarówno Iterable, jak i Stream). Rzeczywiste wykonanie ciała zaczyna się dopiero, gdy spróbujemy uzyskać wartość po raz pierwszy. Gdy osiągnięte zostanie słowo kluczowe yield, wartość jest przekazywana "na zewnątrz", a stan funkcji jest zapisywany. Wykonanie ciała jest wstrzymane. Przy następnym próbie uzyskania wartości, wykonanie jest wznawiane z miejsca, w którym zostało zatrzymane, aż do następnego yield lub końca funkcji.

Różnice:

Cecha sync* (Synchronous) async* (Asynchronous)
Typ zwracany Iterable Stream
Słowa kluczowe sync*, yield async*, yield, yield*
Użycie await Nie można Można
Wstrzymanie Do żądania następnej wartości Do pojawienia się kolejnego zdarzenia asynchronicznego