Funkcje Generatora w TypeScript
Ten artykuł wyjaśnia funkcje generatora w TypeScript.
Możesz nauczyć się wszystkiego, począwszy od podstaw korzystania z funkcji generatorowych, aż po zaawansowane przykłady połączone z przetwarzaniem asynchronicznym, wraz z fragmentami kodu.
YouTube Video
Funkcje Generatora
Funkcje generatora w TypeScript oferują podobną funkcjonalność jak funkcje generatora w JavaScript. Funkcje generatora definiuje się za pomocą function*
(deklaracja funkcji z gwiazdką) i są to specjalne funkcje, które mogą wstrzymywać i wznawiać wykonanie, w przeciwieństwie do zwykłych funkcji.
Kiedy wywoływana jest funkcja generatora, zwracany jest iterator, który generuje wartości jedna po drugiej za pomocą iteratora, a wykonanie można wstrzymać za pomocą słowa kluczowego yield
lub przesyłać wartości z zewnątrz.
Podstawowa składnia funkcji generatora
1function* myGenerator(): Generator<number, void, unknown> {
2 yield 1;
3 yield 2;
4 yield 3;
5}
6
7const gen = myGenerator();
8
9console.log(gen.next().value); // 1
10console.log(gen.next().value); // 2
11console.log(gen.next().value); // 3
12console.log(gen.next().done); // true (Iteration finished)
- Zdefiniuj funkcję generatora za pomocą
function* myGenerator()
. - Słowo kluczowe
yield
wstrzymuje wykonanie funkcji, zwracając jednocześnie wartość. - Za każdym razem, gdy wywoływana jest metoda
next()
, wykonanie funkcji generatora jest wznawiane i przechodzi do następnegoyield
.
next()
zwraca obiekt zawierający następną wartość oraz właściwość done
. Kiedy done
jest równe true
, oznacza to, że wszystkie wartości zostały wygenerowane i przetwarzanie generatora zostało zakończone.
Zastosowania funkcji generatora
Korzystanie z funkcji generatora umożliwia łatwe przedstawienie przetwarzania sekwencyjnego. W poniższym przykładzie tworzymy funkcję generatora, która generuje sekwencję liczb.
1function* sequenceGenerator(start: number = 0, step: number = 1) {
2 let current = start;
3 while (true) {
4 yield current;
5 current += step;
6 }
7}
8
9const seq = sequenceGenerator(1, 2);
10
11console.log(seq.next().value); // 1
12console.log(seq.next().value); // 3
13console.log(seq.next().value); // 5
- W tym przykładzie
sequenceGenerator
generuje nieskończenie rosnącą sekwencję liczb. Użyjyield
, aby zwrócić wartości na każdym kroku, i generuj kolejną wartość w kolejnych wywołaniach.
Przekazywanie wartości do next
Metoda next()
może otrzymać wartość, która może zostać przesłana do funkcji generatora.
1function* adder() {
2 const num1 = yield;
3 const num2 = yield;
4 yield num1 + num2;
5}
6
7const addGen = adder();
8addGen.next(); // Initialization
9addGen.next(5); // Set 5 to num1
10const result = addGen.next(10).value; // Set 10 to num2 and get result
11console.log(result); // 15
- W tym przykładzie
next(5)
inext(10)
przesyłają swoje wartości do funkcji generatora, ayield num1 + num2
zwraca ich sumę.
return
i throw
return(value)
może zakończyć generator i zwrócić określoną wartość.throw(error)
może wyrzucić wyjątek wewnątrz generatora, stosowany do obsługi wyjątków w obrębie generatora.
1function* testGenerator() {
2 try {
3 yield 1;
4 yield 2;
5 } catch (e) {
6 console.error("Error caught:", e);
7 }
8}
9
10const gen = testGenerator();
11console.log(gen.next().value); // 1
12gen.throw(new Error("An error occurred!")); // Error caught: An error occurred!
- W tym przykładzie metoda
throw
jest używana do wygenerowania błędu wewnątrz generatora, a ten błąd jest przechwytywany w obrębie generatora.
Definicja typów w TypeScript
Definicję typu funkcji generatora można określić w następującym formacie.
1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3 yield 1;
4 yield 2;
5 yield 3;
6}
- Określasz typy w formie
Generator<YieldType, ReturnType, NextType>
.YieldType
to typ wartości zwracanej przezyield
.ReturnType
to typ wartości zwracanej przezreturn
.NextType
to typ wartości przekazywanej donext()
.
W poniższym przykładzie określono konkretne typy, aby bezpiecznie korzystać z generatora z zastosowaniem typów.
1function* numberGenerator(): Generator<number, void, number> {
2 const num1 = yield 1;
3 const num2 = yield num1 + 2;
4 yield num2 + 3;
5}
6
7const gen = numberGenerator();
8
9console.log(gen.next().value); // 1
10console.log(gen.next(10).value); // 12 (10 + 2)
11console.log(gen.next(20).value); // 23 (20 + 3)
Generatory i przetwarzanie asynchroniczne
Generatory mogą być również wykorzystywane do przetwarzania asynchronicznego. Na przykład możesz użyć yield
, aby poczekać na wyniki operacji asynchronicznych, jednocześnie kontynuując przetwarzanie sekwencyjne. Jednak w TypeScript lub JavaScript częściej stosuje się async/await
.
1function* asyncTask() {
2 const result1 = yield fetch("https://codesparklab.com/json/example1.json");
3 console.log(result1);
4
5 const result2 = yield fetch("https://codesparklab.com/json/example2.json");
6 console.log(result2);
7}
Chociaż możesz przetwarzać operacje asynchroniczne sekwencyjnie za pomocą generatorów, nie są one powszechnie używane w przetwarzaniu asynchronicznym, ponieważ Promisy i async
/await
są bardziej wygodne.
Podsumowanie
- Funkcje generatorowe to specjalne funkcje zdefiniowane za pomocą
function*
, które mogą zwracać wartości za pomocąyield
, jednocześnie wstrzymując wykonywanie funkcji. - Użyj
next()
, aby wznowić generator i otrzymać wartości. Dodatkowo możesz przesyłać wartości do generatora, używającnext(value)
. - Możesz używać
return()
ithrow()
, aby zakończyć funkcje generatorowe lub obsłużyć błędy. - Podczas korzystania z generatorów w TypeScript możesz używać definicji typów, aby pisać kod bezpieczny typowo.
Generatory to potężne narzędzia, które pozwalają elastycznie kontrolować iterację.
Możesz śledzić ten artykuł, korzystając z Visual Studio Code na naszym kanale YouTube. Proszę również sprawdzić nasz kanał YouTube.