Jaki jest wynik całego wyrażenia yield przekazanego do zmiennej ? Nic lub Niezdefiniowane …
Dlaczego ? Począwszy od drugiej next(), poprzedni yield jest zastępowany argumentami przekazywanymi w następnej funkcji. Ponieważ, nie przekazujemy niczego w następnej metodzie, zakładamy, że całe 'poprzednie wyrażenie yield’ jest niezdefiniowane.
Mając to na uwadze, przeskoczmy do następnej sekcji, aby zrozumieć więcej o przekazywaniu argumentów do metody next().
Przekazywanie argumentów do metody next()
W odniesieniu do schematu blokowego powyżej, porozmawiajmy o przekazywaniu argumentów do następnej funkcji. Jest to jedna z najtrudniejszych części implementacji całego generatora.
Rozważmy następujący fragment kodu, gdzie yield jest przypisany do zmiennej, ale tym razem przekazujemy wartość w metodzie next().
Spójrzmy na poniższy kod w konsoli. A zaraz po nim wyjaśnienie.
Wyjaśnienie:
- Gdy wywołujemy pierwszą metodę next(20), wypisywana jest każda linia kodu aż do pierwszego yield. Ponieważ nie mamy żadnego wcześniejszego wyrażenia yield ta wartość 20 jest odrzucana. Na wyjściu otrzymujemy wartość yield jako i*10, czyli tutaj 100. Również stan wykonania zatrzymuje się na pierwszym yield, a const j nie jest jeszcze ustawione.
- Drugie wywołanie next(10), zastępuje całe pierwsze wyrażenie yield wartością 10, imagine yield (i * 10) = 10, które przechodzi do ustawienia wartości const j na 50 przed zwróceniem wartości drugiego yield. Wartość yield wynosi tutaj 2 * 50 / 4 = 25.
- Trzeci next(5), zastępuje całe drugie wyrażenie yield wartością 5, sprowadzając wartość k do 5. I dalej kontynuuje wykonywanie instrukcji return i zwraca (x + y + z) => (10 + 50 + 5) = 65 jako końcową wartość yield wraz z wykonanym true.
To może być trochę przytłaczające dla czytelników po raz pierwszy, ale poświęć dobre 5 minut na przeczytanie tego w kółko, aby całkowicie zrozumieć.
Przekazywanie Yield jako argumentu funkcji
Istnieje n-numer przypadków użycia wokół yield dotyczących tego, jak można go użyć wewnątrz generatora funkcji. Spójrzmy na poniższy kod dla jednego z takich ciekawych przypadków użycia yield, wraz z wyjaśnieniem.
Wyjaśnienie
- Pierwsze next() daje niezdefiniowaną wartość, ponieważ wyrażenie yield nie ma wartości.
- Drugie next() zwraca „I am usless”, wartość, która została przekazana. I przygotowuje argument do wywołania funkcji.
- Trzeci next(), wywołuje funkcję z niezdefiniowanym argumentem. Jak wspomniano powyżej, metoda next() wywołana bez żadnych argumentów w zasadzie oznacza, że całe poprzednie wyrażenie yield jest niezdefiniowane. Stąd, to drukuje undefined i kończy bieg.
Yield z wywołaniem funkcji
Oprócz zwracania wartości yield może również wywoływać funkcje i zwracać wartość lub drukować to samo. Spójrzmy na poniższy kod i zrozumiemy go lepiej.
Kod powyżej zwraca wartość obj jako wartość yield. I kończy bieg przez ustawienie undefined na const user.
Yield z obietnicami
Yield z obietnicami podąża za tym samym podejściem, co wywołanie funkcji powyżej, zamiast zwracać wartość z funkcji, zwraca obietnicę, która może być dalej oceniana pod kątem sukcesu lub porażki. Spójrzmy na poniższy kod, aby zrozumieć, jak to działa.
The apiCall zwraca obietnice jako wartość yield, po rozwiązaniu po 2 sekundach drukuje wartość, której potrzebujemy.
Yield*
Do tej pory przyglądaliśmy się przypadkom użycia wyrażenia yield, teraz przyjrzymy się innemu wyrażeniu zwanemu yield*. Yield*, gdy jest użyte wewnątrz funkcji generatora, deleguje inną funkcję generatora. Po prostu, synchronicznie kończy funkcję generatora w swoim wyrażeniu przed przejściem do następnej linii.
Spójrzmy na kod i wyjaśnienie poniżej, aby lepiej zrozumieć. Ten kod pochodzi z MDN web docs.
Wyjaśnienie
- Pierwsze wywołanie next() daje wartość 1.
- Drugie wywołanie next() jest jednak wyrażeniem yield*, co z natury oznacza, że zamierzamy wykonać inną funkcję generatora określoną w wyrażeniu yield* przed kontynuowaniem bieżącej funkcji generatora.
- W swoim umyśle możesz założyć, że powyższy kod zostanie zastąpiony tak, jak poniższy
function* g2() {
yield 1;
yield 2;
yield 3;
yield 4;
yield 5;
}
To spowoduje zakończenie działania generatora. Istnieje jednak jedna wyraźna zdolność yield*, o której należy pamiętać podczas używania return, w następnej sekcji.
Yield* z return
Yield* z return zachowuje się nieco inaczej niż zwykłe yield*. Kiedy yield* jest używane z deklaracją return, ocenia do tej wartości, co oznacza, że cała funkcja yield*() staje się równa wartości zwróconej z powiązanej funkcji generatora.
Spójrzmy na kod i wyjaśnienie poniżej, aby lepiej to zrozumieć.
Wyjaśnienie
- W pierwszym next() przechodzimy od razu do yield 1 i zwracamy jego wartość.
- Drugie next() zwraca 2.
- Trzecie next(), zwraca 'foo’ i przechodzi do yield 'the end’, przypisując po drodze 'foo’ do wyniku const.
- Ostatnia next() kończy działanie.
Yield* z wbudowanym obiektem iterowalnym
Jest jeszcze jedna interesująca właściwość yield* warta wspomnienia, podobna do wartości zwracanej, yield* może również iterować po obiektach iterowalnych takich jak Array, String i Map.
Przyjrzyjmy się jak to działa w czasie rzeczywistym.
Tutaj w kodzie yield* iteruje nad każdym możliwym obiektem iterowalnym, który jest przekazywany jako jego wyrażenie. Myślę, że sam kod nie wymaga wyjaśnień.
Najlepsze praktyki
Na dodatek do tego wszystkiego, każdy iterator/generator może być iterowany nad pętlą for…of. Podobnie do naszej metody next(), która jest wywoływana jawnie, pętla for…of wewnętrznie przechodzi do następnej iteracji bazując na słowie kluczowym yield. I iteruje tylko do ostatniego yield i nie przetwarza instrukcji return jak metoda next().
Możesz zweryfikować to samo w poniższym kodzie.
Końcowa wartość zwracana nie jest drukowana, ponieważ pętla for…of iteruje tylko do ostatniego yield. Tak więc, jest to najlepsza praktyka, aby uniknąć instrukcji return wewnątrz funkcji generatora, ponieważ wpłynęłoby to na możliwość ponownego użycia funkcji, gdy jest ona iterowana przez for…of.
Zakończenie
Mam nadzieję, że to pokrywa podstawowe przypadki użycia funkcji generatora i mam szczerą nadzieję, że dało lepsze zrozumienie jak działają generatory w JavaScript ES6 i wyżej. Jeśli podoba Ci się moja treść proszę zostaw 1, 2, 3 lub nawet 50 klapsów :).
Proszę śledzić mnie na moim koncie GitHub po więcej projektów JavaScript i Full-Stack:
.