Rekurze v šablonách Ember.js, case factorial(n)

Faktorální

The produkt z (=výsledek) a celé číslo a všechny celá čísla pod tím

Čtyři faktoriály (4 x 3 x 2 x 1) jsou 24

Cíl

Vytvořte faktoriální komponentu, která bude počítat odpověď rekurzivně pouze pomocí šablon a pomocníci .

Krok 1 – Jak vypočítat faktoriál pomocí rekurze

Podívejme se nejprve, jak vyřešit faktoriál pomocí rekurze v JS zemi

function factorial(number) {
  if(number === 0) return 1; //when we get to the base case it returns 1.
  return number * factorial(number-1) //Recursion, we are calling factorial again with n-1
}

factorial(3) //6

Krok 2 – Faktorová složka

Napíšeme totéž, ale pomocí šablon ember (toto není konečná verze) je účelem ukázat podobnost s ekvivalentem js

ekv je pomocník pro testování rovnosti {{eq "hola" "bye"}} = false

sub je pomocník k odečtení něčeho {{sub 5 1}} = 4

více je pomocník k vynásobení něčeho {{mult 5 2}} = 10

Tyto a další pomocníky najdete na

žhaví-matematickí-pomocníci

uhlík-pravda-pomocníci

{{! factorial.hbs}}
{{#if (eq @number 0)}}
    {{return 1}} {{! when we get the base case, it retuns 1.}}
{{else}}
    {{return 
        (mult @number <Factorial @number={{sub @number 1}} />)
  }} {{! Recursion, we're calling factorial again with n-1}}
{{/if}}

Tento algoritmus se zdá správný a koncepčně je stejný jako JS ekvivalentní, ale obsahuje některé chyby.

Za prvé, když chcete return něco v ember šablonách, použijete yield klíčové slovo místo return

{{! factorial.hbs}}
{{#if (eq @number 0)}}
    {{yield 1}} {{! when we get to the base case, return 1.}}
{{else}}
    {{yield 
        (mult @number <Factorial @number={{sub @number 1}} />)
  }} {{! Recursion, we're calling factorial again with n-1}}
{{/if}}

Nakonec je to ta obtížná část, kde se ocitáme trochu ztraceni, zatímco ve skutečnosti může poskytnout nebo „vrátit“ součást

{{yield (component 'factorial' @number=(sub @number 1)}}

Tato komponenta by se ve skutečnosti nespustila, takže klient tohoto kódu by musel udělat něco takového.

{{#let 10 as |number|}}
  <Factorial @number={{number}} as |Factorial|>
        <Factorial />
  </Factorial>
{{/let}}

Což vlastně nic nedělá, protože nikdy nedostaneme odpověď.

Tady je řešení

{{! factorial.hbs}}
{{#if (eq @number 0)}}
    {{yield 1}} {{! when we get to the base case, return 1.}}
{{else}}
    {{! Recursion, we are calling factorial component again with n-1}}
    <Factorial @number={{sub @number 1}} as |answer|> 
        {{yield (mult @number answer)}} 
    </Factorial>
{{/if}}

Vynásobením aktuálního čísla odezvou jiného faktoriálu (n-1) (uvnitř bloku) , právě jsme pokryli rekurzi.

Zde je konečná komponenta "API".

{{#let 10 as |number|}}
  <Factorial @number={{number}} as |answer|>
        <h1>{{number}}! is {{answer}}</h1>
  </Factorial>
{{/let}}

Nakonec, pokud chceme vizuálně zobrazit nebo vykreslit rekurzivní strom pěkně, můžeme použít <ul> štítek

{{! factorial.hbs}}
{{#let
  (array "red" "blue" "yellow" "orange" "pink") as |colors|
}}
  <ul style="background-color: {{object-at (mod (sub @number 1) colors.length) colors}};">
    {{#if (eq @number 0)}}
      {{yield 1}} {{! when we get to the base case, return 1.}}
    {{else}}
      {{@number}} * factorial({{sub @number 1}})
      {{! Recursion, we are calling factorial component again with n-1}}
      <Factorial @number={{sub @number 1}} as |response|> 
        {{yield (mult @number answer)}} 
      </Factorial>
    {{/if}}
  </ul>
{{/let}}

A inspektor Ember by vypadal takto!

Zde je ukázka

Proč používat šablony místo čistého JavaScriptu?

Šablony Ember se automaticky vykreslí, když nějaká hodnota (musí být @tracked zdobená nemovitost nebo vlastnost Ember.Object) v nich odkazované změny, to znamená, že bychom mohli mít pozorovanou rekurzi. Náš strom komponent může skutečně činit chytrá rozhodnutí, takže můžeme mít rekurzivní logický strom, který přepočítává libovolné události, jako je kliknutí na tlačítko, které by mohlo zvýšit vlastnost, na kterou šablona odkazuje, a spustit překreslení atd. Jinými slovy, můžeme využít toho, že šablony ember již přesně vědí, kdy se mají „překreslit“ jako efektivní pozorovatelé naší rekurze.

Tento druh problémů můžete samozřejmě vyřešit také přidáním pozorovatelů do vaší třídy komponent js nebo jinou technikou, která je obvykle mnohem podrobnější a vyžadovala by nějaký druh ručního zapojení pozorovatelů přes addObserver a pak je zničte, pokud se komponenta zničí.

O našem případu použití

Tento krátký blogový příspěvek je o něčem, co jsem se dnes se svými kolegy naučil, když jsem se pokoušel vypočítat hodnotu pomocí rekurzivní techniky na šablonách žhavých uhlíků , kterou jsme nakonec nepoužili.

Náš případ použití byl velmi zvláštní a specifický, chtěli jsme způsob, jak zmenšit složitý vnořený objekt (sloučit objekt) a vytvořit živý pole, takže klient mohl iterovat dál. Tento „živý“ obsah by používal šablony "pozorovatelnost" a automatické "vykreslování" pro efektivní pozorování externí závislosti, tj. DS.Model instanci, protože proces zploštění má logické větve založené na DS.Model vlastnosti skutečné hodnoty (odkazované v šablonách). Od jakékoli změny v DS.Model by způsobilo kompletní překreslení a dopady na výkon byly hrozné, zvolili jsme jinou cestu.