Recenze

Zjistěte, jak funguje alternátor, jednoduše

Normální funkce vracejí pouze jednu hodnotu (nebo nic).

Generátory mohou podle potřeby vracet více hodnot jednu po druhé. Generátory fungují dobře s iterovatelnými objekty a usnadňují vytváření datových streamů.

Funkce generátoru

Pro deklaraci generátoru se používá speciální syntaktická konstrukce: function* , která se nazývá „generátorová funkce“.

Vypadá to takto:

funkce* generujeSequence()

Generátorové funkce se chovají odlišně od běžných funkcí. Když je generátorová funkce volána, neprovede se její kód. Místo toho se vrátí speciální objekt nazývaný „generátor“, který řídí její provádění.

function* generateSequence() < yield 1; yield 2; return 3; >// "функция-генератор" создаёт объект "генератор" let generator = generateSequence(); alert(generator); // [object Generator]

Provádění funkčního kódu ještě nezačalo:

Hlavní metodou generátoru je next(). Po jejím zavolání se spustí provádění kódu až do nejbližší instrukce yield (hodnota může chybět, v takovém případě se předpokládá, že je nedefinovaná). Po dosažení instrukce yield se provádění funkce pozastaví a odpovídající hodnota se vrátí do externího kódu:

Výsledkem metody next() je vždy objekt se dvěma vlastnostmi:

  • hodnota : hodnota z výnosu .
  • done: true, pokud je provádění funkce dokončeno, jinak false.

Například zde vytvoříme generátor a získáme první z jeho návratových hodnot:

funkce* generateSequence() < yield 1; yield 2; return 3; >let generator = generateSequence(); let one = generator.next(); alert(JSON.stringify(one)); //

V tomto bodě jsme obdrželi pouze první hodnotu, provádění funkce je zastaveno na druhém řádku:

Opětovné volání generator.next() obnoví provádění kódu a vrátí výsledek dalšího yield:

nechť two = generator.next(); alert(JSON.stringify(two)); //

A nakonec poslední volání ukončí funkci a vrátí výsledek:

nechť tři = generátor.next(); alert(JSON.stringify(tři)); //

Generátor je nyní plně spuštěn. Vidíme to podle vlastnosti done:true a za konečný výsledek považujeme hodnotu value:3.

Nová volání funkce generator.next() již nedávají smysl. Pokud ano, nezpůsobí chybu, ale vrátí stejný objekt: .

Funkce* f(…) nebo funkce *f(…)?

Není mezi nimi žádný rozdíl, obě syntaxe jsou správné.

Obvykle je ale vhodnější první možnost, protože hvězdička označuje typ deklarované entity (function* – „generátorová funkce“), a nikoli její název, takže dává smysl umístit ji blízko slova function.

Výčet generátorů

Jak jste asi uhodli z přítomnosti metody next(), generátory jsou iterovatelné objekty.

Hodnoty, které vracejí, lze iterovat pomocí for..of:

function* generateSequence() < yield 1; yield 2; return 3; >let generator = generateSequence(); for(let value of generator) < alert(value); // 1, затем 2 >

Vypadá to mnohem hezčeji než použití .next().value , že?

. Ale poznámka: výše uvedený příklad vytiskne hodnotu 1, poté 2. Hodnota 3 se nevytiskne!

Je to proto, že iterace for..of ignoruje poslední hodnotu, což se provede: true. Takže pokud chceme, aby všechny hodnoty byly při iteraci for..of zachovány, musíme je vrátit pomocí yield:

function* generateSequence() < yield 1; yield 2; yield 3; >let generator = generateSequence(); for(let value of generator) < alert(value); // 1, затем 2, затем 3 >

Protože generátory jsou iterovatelné objekty, můžeme použít všechny funkce s nimi spojené, jako například operátor rozložení:

function* generateSequence() < yield 1; yield 2; yield 3; >let sequence = [0, . generateSequence()]; alert(sequence); // 0, 1, 2, 3

Ve výše uvedeném kódu funkce .generateSequence() přemění iterovatelný objekt generátoru na pole prvků (více informací o operátoru rozložení naleznete v kapitole Zbývající parametry a operátor rozložení).

Použití generátorů pro iterovatelné objekty

Před časem jsme v kapitole o iterovatelných objektech vytvořili iterovatelný rozsah objektů, který vrací hodnoty od. do.

Připomeňme si kód:

let range = < from: 1, to: 5, // for..of range вызывает этот метод один раз в самом начале [Symbol.iterator]() < // . он возвращает перебираемый объект: // далее for..of работает только с этим объектом, запрашивая следующие значения return < current: this.from, last: this.to, // next() вызывается при каждой итерации цикла for..of next() < // нужно вернуть значение как объект if (this.current ; >else < return < done: true >; > > >; > >; // при переборе объекта range будут выведены числа от range.from до range.to alert([. range]); // 1,2,3,4,5

Pro iteraci můžeme použít generátorovou funkci jejím zadáním v Symbol.iterator.

Zde je stejný rozsah, ale s mnohem kompaktnějším iterátorem:

let range = < from: 1, to: 5, *[Symbol.iterator]() < // краткая запись для [Symbol.iterator]: function*() for(let value = this.from; value >>; alert( [. range] ); // 1,2,3,4,5

To funguje, protože range[Symbol.iterator]() nyní vrací generátor a jeho metody jsou přesně to, co for..of očekává:

  • má metodu .next()
  • který vrací hodnoty ve tvaru

To samozřejmě není náhoda. Generátory byly do jazyka JavaScript přidány částečně proto, aby se usnadnilo vytváření iterovatelných objektů.

Generátorová verze je mnohem kratší než původní verze s iterovatelným rozsahem a zachovává si stejnou funkcionalitu.

Generátory mohou generovat nekonečně

Ve výše uvedených příkladech jsme generovali konečné posloupnosti, ale můžeme také vytvořit generátor, který vrací hodnoty nekonečně. Například nekonečnou posloupnost pseudonáhodných čísel.

Samozřejmě budeme pro takový generátor potřebovat break (nebo return) ve smyčce for..of, jinak bude smyčka pokračovat donekonečna a skript se „zamrzne“.

Složení generátorů

Složení generátoru je speciální funkce generátorů, která umožňuje transparentně „vkládat“ generátory do sebe navzájem.

Například máme funkci pro generování posloupnosti čísel:

funkce* generujeSequence(začátek, konec)

Chtěli bychom ho použít k vygenerování složitější sekvence:

  • nejprve čísla 0..9 (s kódy znaků 48…57)
  • následované velkými písmeny A..Z (kódy znaků 65…90)
  • následovaná písmeny abecedy a..z (kódy znaků 97…122)

Takovou sekvenci můžeme použít k vygenerování hesel, vybrat z ní znaky (možná přidat interpunkční znaménka), ale nejdříve ji musíme vygenerovat.

V normální funkci, abychom zkombinovali výsledky z několika dalších funkcí, tyto funkce zavoláme, uložíme mezivýsledky a na konci je zkombinujeme.

Generátory mají speciální syntaxi yield* , která umožňuje “vnořovat” generátory jeden do druhého (provádět jejich skládání).

Zde je generátor se složením:

function* generateSequence(start, end) < for (let i = start; i function* generatePasswordCodes() < // 0..9 yield* generateSequence(48, 57); // A..Z yield* generateSequence(65, 90); // a..z yield* generateSequence(97, 122); >let str = ''; for(let code of generatePasswordCodes()) < str += String.fromCharCode(code); >alert(str); // 0..9A..Za..z

direktiva yield* delegáti provedení do jiného generátoru. Tento termín znamená, že yield* gen iteruje přes generátor gen a transparentně směruje jeho výstup ven. Jako by hodnoty byly generovány externím generátorem.

Výsledek je stejný, jako kdybychom vložili kód z vnořených generátorů:

function* generateSequence(start, end) < for (let i = start; i function* generateAlphaNum() < // yield* generateSequence(48, 57); for (let i = 48; i let str = ''; for(let code of generateAlphaNum()) < str += String.fromCharCode(code); >alert(str); // 0..9a..zA..Z

Skládání generátorů je přirozený způsob, jak vložit výstup jednoho generátoru do proudu jiného. Nepoužívá další paměť k ukládání mezivýsledků.

výnos – silnice v obou směrech

Až doposud byly generátory velmi podobné iterovatelným objektům se speciální syntaxí pro generování hodnot. Ve skutečnosti jsou však mnohem výkonnější a flexibilnější.

Věc se má tak, že yield je obousměrná ulice: nejen vrací výsledek ven, ale také může předat hodnotu zvenčí do generátoru.

Abychom to mohli udělat, musíme zavolat generator.next(arg) s argumentem. Tento argument se stane výsledkem yield.

Ukažme si to na příkladu:

function* gen() < // Передаём вопрос во внешний код и ожидаем ответа let result = yield "2 + 2 = ?"; // (*) alert(result); >let generator = gen(); let question = generator.next().value; // передаём результат в генератор
  1. První volání funkce generator.next() je vždy bez argumentu, spustí provádění a vrátí výsledek prvního yield “2+2=?”. V tomto okamžiku generátor pozastaví provádění.
  2. Pak, jak je znázorněno na obrázku výše, je výsledek funkce yield předán vnějšímu kódu do proměnné question.
  3. S generator.next(4) se provádění generátoru obnoví a jako výsledek přiřazení se dostane číslo 4: let result = 4 .

V externím kódu nemusí být funkce next(4) volána okamžitě. Může to chvíli trvat. To není problém, generátor počká.

// возобновить генератор через некоторое время setTimeout(() => generator.next(4), 1000);

Jak vidíte, na rozdíl od běžných funkcí může generátor sdílet výsledky s volajícím kódem předáváním hodnot funkci next/yield.

Aby bylo to zřejmější, co se děje, zde je další příklad s více voláními:

function* gen() < let ask1 = yield "2 + 2 = ?"; alert(ask1); // 4 let ask2 = yield "3 * 3 = ?" alert(ask2); // 9 >let generator = gen(); alert( generator.next().value ); // "2 + 2 = ?" alert( generator.next(4).value ); // "3 * 3 = ?" alert( generator.next(9).done ); // true
  1. První .next() se začne provádět… Dostane se k prvnímu yield .
  2. Výsledek se vrátí do externího kódu.
  3. Druhá funkce .next(4) předá hodnotu 4 zpět generátoru jako výsledek prvního yield a obnoví provádění.
  4. . Dosáhne se druhého yield , který se stane výsledkem .next(4) .
  5. Třetí funkce next(9) předá generátoru hodnotu 9 jako výsledek druhého yield a obnoví provádění, které končí s koncem funkce, tedy hotovo: true.

Toto je hra ping-pong: každá next(value) předá generátoru hodnotu, která se stane výsledkem aktuálního yield, obnoví provádění a získá výraz z dalšího yield.

generátor.hod

Jak jsme viděli ve výše uvedených příkladech, externí kód může předat hodnotu do generátoru jako výsledek funkce yield.

. Ale výsledek můžete nejen předat, ale také iniciovat chybu. To je přirozené, protože chyba je druh výsledku.

Abychom mohli předat chybu funkci yield, musíme zavolat generator.throw(err). V tomto případě bude na řádku s yield vyvolána výjimka err.

Například zde yield “2 + 2 = ?” vyvolá chybu:

function* gen() < try < let result = yield "2 + 2 = ?"; // (1) alert("Выполнение программы не дойдёт до этой строки, потому что выше возникнет исключение"); >catch(e) < alert(e); // покажет ошибку >> let generator = gen(); let question = generator.next().value; generator.throw(new Error("Ответ не найден в моей базе данных")); // (2)

Chyba, která je vyvolána do generátoru na řádku (2), má za následek výjimku na řádku (1) s yield. Ve výše uvedeném příkladu ji try..catch zachytí a zobrazí.

Pokud ji nechceme zachytit, tak jako každá normální výjimka „vypadne“ z generátoru do externího kódu.

Aktuální řádek volajícího kódu je řádek s generator.throw, označený (2). Můžeme ho tedy zachytit ve vnějším kódu takto:

function* generate() < let result = yield "2 + 2 = ?"; // Ошибка в этой строке >let generator = generate(); let question = generator.next().value; try < generator.throw(new Error("Ответ не найден в моей базе данных")); >catch(e) < alert(e); // покажет ошибку >

Pokud chyba není zachycena tam, pak jako obvykle vypadne a pokud není zachycena, „zhroutí“ skript.

Celkem

  • Generátory se vytvářejí pomocí generátorových funkcí function* f(…).
  • V rámci generátorů, a pouze v rámci generátorů, existuje operátor yield.
  • Externí kód a generátor si vyměňují mezivýsledky prostřednictvím volání next/yield.

Generátory se v moderním JavaScriptu používají jen zřídka. Někdy jsou ale užitečné, protože schopnost funkce vyměňovat si data s volajícím za běhu je poměrně unikátní. A samozřejmě pro vytváření iterovatelných objektů.

V další kapitole se budeme také zabývat asynchronními generátory, které se používají ke čtení proudů asynchronně generovaných dat (například stránkovaných dat stahovaných ze sítě) v cyklu for await.

Ve webovém programování často pracujeme s datovými toky, takže se jedná o další důležitý případ použití.

úkoly

Pseudonáhodný generátor

Existuje mnoho oblastí, kde potřebujeme náhodná data.

Jedním z nich je testování. K dobrému otestování všeho můžeme potřebovat náhodná data: text, čísla atd.

V JavaScriptu můžeme použít Math.random(). Pokud se ale něco pokazí, musíme test spustit znovu se stejnými daty.

K tomu se používají tzv. „generátory pseudonáhodných čísel se semínky“. Ty přijmou „semeno“ jako první hodnotu a poté vygenerují další pomocí vzorce. Stejné semeno tedy produkuje stejnou sekvenci, a proto je celý proud snadno reprodukovatelný. Pro reprodukci sekvence si stačí pamatovat pouze semeno.

Příklad takového vzorce, který generuje víceméně rovnoměrně rozložené hodnoty:

next = previous * 16807 % 2147483647

Pokud jako počáteční hodnotu použijeme 1, hodnoty budou:

  1. 16807
  2. 282475249
  3. 1622650073
  4. …a tak dále…

Úkolem je vytvořit generátorovou funkci pseudoRandom(seed), která přijme seed a vytvoří generátor se zadaným vzorcem.

let generator = pseudoRandom(1); alert(generator.next().value); // 16807 alert(generator.next().value); // 282475249 alert(generator.next().value); // 1622650073

Generátor přeměňuje mechanickou energii na elektrickou, ale jak přesně k tomuto procesu dochází? Děje se toto: když se cívka otáčí v magnetickém poli, indukuje se v ní elektromotorické síla, která způsobuje tok proudu v určitém směru (směr proudu závisí na směru otáčení cívky nebo směru magnetického pole a jeho směr lze určit pravidlem pravé ruky).

Představte si žárovku, jejíž konce jsou připojeny k cívce rotující v magnetickém poli. Pokaždé, když se změní proud procházející cívkou, protéká proud, který způsobí rozsvícení žárovky. To je jistě jeden ze způsobů výroby elektřiny, ale v takovém zařízení se cívka v důsledku neustálého kroucení zlomí. Zde přichází na řadu použití „kartáčových kontaktů“. (Viz obrázek níže, toto je příklad základního neboli jednoobvodového generátoru).

Co jsou to „kartáčové kontakty“ a k čemu se používají?

Na koncích cívky se používají kartáčové kontakty a kontakty, běžně známé jako sběrné kroužky. Sběrné kroužky slouží k vytvoření elektrického kontaktu mezi stacionárními a rotujícími vodiči, což umožňuje stacionárnímu zdroji energie přenášet energii do rotující části. Sběrné kroužky slouží ke sběru střídavého elektromotorického napětí z vinutí, které je poté sbíráno uhlíkovými kartáči do vnějšího obvodu.

Proměnné polohy smyčky: Změna úhlu během otáčení mezi kolmicí cívky a siločarami magnetického pole způsobuje změnu velikosti generovaného elektromotorického napětí. Toto elektromotorické napětí také závisí na rychlosti změny magnetického toku cívkou. Obrázek níže ukazuje různé polohy cívky od 0 do 180 stupňů a poté od 180 do 360 stupňů. V poloze 0 stupňů: Tato poloha je také známá jako „neutrální rovina“; v této poloze je smyčka rovnoběžná s magnetickými siločarami a cívkou prochází maximální tok. Nedochází však k produkci elektromotorického pole, protože nedochází ke „změně toku smyčkou“.V poloze 90 stupňů: Poté, co byla smyčka otočena o 90 stupňů ve směru hodinových ručiček magnetickým polem, byla vazba magnetického toku skrz ni nulová. Rychlost změny magnetického toku skrz ni však byla maximální, což způsobilo, že indukované elektromotorické síly vzrostly z nuly na svou maximální hodnotu.Na 180 stupňů. Pozice: Cívka se opět otočí o 90 stupňů ve směru hodinových ručiček a dokončí tak smyčku o 180 stupňů. V tomto případě je smyčka kolmá k magnetickým siločarám, což znamená, že jí prochází maximální hustota magnetického toku. Elektromagnetické pole klesá na nulu. Poloha při 270 stupních: Před 180stupňovým cyklem zůstávala polarita napětí stejná, protože „kotva vodiče procházejícího jižním magnetickým polem byla stejná“, ale nyní se polarita změní, protože „tato kotva nyní protne severní magnetické pole“ a naopak. Při 270 stupních je vazba magnetického toku smyčkou opět nulová, ale rychlost změny magnetického toku je maximální. V této poloze dosahuje indukované elektromotorické napětí své vrcholové hodnoty, ale tentokrát v opačném směru. 360stupňová poloha: Smyčka se otočí o dalších 90 stupňů, čímž dokončí rotaci o 360 stupňů. Smyčka se vrátí do původní polohy, magnetická vazba skrz ni je maximální a napětí opět klesne na nulu.

Tento typ produkovaného napětí je střídavé napětí.

Co znamená termín „elektromagnetismus“? Faradayův zákon elektromagnetické indukce stavů

  1. Jak funguje elektrické uzemnění?
  2. Co je volání přes WiFi? Jak to funguje?
  3. Jak funguje detekce částečných výbojů v rozváděčích?
  4. Jak funguje kartáčový stejnosměrný motor
  5. Co je 3D tisk? — Typy a jak to funguje
  6. Co je obloukové svařování? — Typy a jak to funguje
  7. Co je bodové svařování? — Definice toho, jak to funguje
  8. Co je to CNC vyvrtávačka a jak funguje?
  9. Jak to funguje: Volnoběžná spojka
  10. Jak funguje ohýbačka trubek?

Zjistěte, proč se otáčky stropních ventilátorů zpomalují Přemýšleli jste někdy, proč se vaše stropní ventilátory časem zpomalují? A nakonec se začnou otáčet velmi pomalu nebo přestanou fungovat. Ve skutečnosti existují dva důvody, proč se vaše stropní ventilátory zpomalují. 1) Kapacita začíná ztrácet svůj výkon

Co je frézování závitů a jak funguje závitová fréza | Jak řezat závity | CNCSOUSTRUŽENÍ Frézování závitů je všestranné a praktické řešení pro výrobu závitů a CNC frézování je proces zejména pro velké otvory. Tento proces se v mnoha případech obecně používá místo řezání závitů. Jaké jsou výhody frézování závitů? V této příručce se budeme zabývat.

Jak funguje proces montáže desek plošných spojů? 31. srpna 2017 Bezchybně funkční deska plošných spojů (PCB) je výsledkem pečlivého montážního procesu. Deska musí projít několika fázemi výrobního procesu. Kdo to je? Čtěte dále a dozvíte se to. Jaké jsou fáze montáže desek plošných spojů? Montáž desek plošných spojů (PCBA) se skládá z

Jak funguje dvoustupňové čerpadlo? Pokud jste jako většina majitelů domů, pravděpodobně víte, jak funguje vodní čerpadlo – tlačí vodu z nádrže potrubím do vašeho domu. Ale co se přesně děje uvnitř tohoto dvoustupňového čerpadla? V tomto článku se podíváme na to, jak funguje, a pochopíme, jak důležité je jeho dostatečné.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button